First version of the VMime Book.

This commit is contained in:
Vincent Richard 2005-11-06 16:16:15 +00:00
parent c179a10068
commit 7a3b1fe471
13 changed files with 4268 additions and 0 deletions

View File

@ -2,6 +2,10 @@
VERSION 0.7.2cvs
================
2005-11-06 Vincent Richard <vincent@vincent-richard.net>
* First version of the VMime Book.
2005-11-05 Vincent Richard <vincent@vincent-richard.net>
* Refactored header field values and parameters.

19
doc/book/Makefile Normal file
View File

@ -0,0 +1,19 @@
all: convert-images book
convert-images:
cd images ; make
# Full build: multiple runs for correct references...
book:
pdflatex book.tex
pdflatex book.tex
pdflatex book.tex
# Only one run for development (faster)
book-dev:
pdflatex book.tex
clean:
rm -f *.toc *.aux *.lof *.log *.lol *.pdf

812
doc/book/basics.tex Normal file
View File

@ -0,0 +1,812 @@
\chapter{Basics}
% ============================================================================
\section{Reference counting}
\subsection{Introduction} % --------------------------------------------------
Since version 0.7.2cvs, VMime use smart pointers to simplify memory
management. VMime's smart pointer implementation relies on
RAII\footnote{Ressource Allocation is Initialisation} so that we do not need
to bother with deleting an object (freeing memory) when it is not used
anymore.
There are two possibilities for owning a reference to an object. We can own a
strong reference to an object: as long as we keep this reference, the object
is not destroyed. Or we can own a weak reference to the object: the object can
be destroyed if nobody owns a strong reference to it, in which case the weak
reference becomes invalid.
An object is destroyed as soon as the last strong reference to it is released.
At the same tine, all weak references (if any) are automatically set to point
to \vnull.
In VMime, these two types of references are known as {\vcode vmime::ref}
and {\vcode vmime::weak\_ref}, respectively.
\subsection{Instanciating reference-counted objects} % -----------------------
In VMime, all objects that support reference counting inherit from the
{\vcode vmime::object} class, which is responsible for
incrementing/decrementing the counter and managing the object's life cycle.
If you want to create a smart pointer to a new object instance, you should
use the function {\vcode vmime::create} instead of the {\vcode new}
operator.
\begin{lstlisting}[caption={Smarts pointers and creating objects}]
class myObject : public vmime::object
{
public:
myObject(const vmime::string& name)
: m_name(name)
{
}
void sayHello()
{
std::cout << "Hello " << m_name << std::endl;
}
private:
vmime::string m_name;
};
int main()
{
vmime::ref <myObject> obj =
vmime::create <myObject>("world");
obj->sayHello();
return 0;
} // Here, 'obj' gets automatically destroyed
\end{lstlisting}
\subsection{Using smart pointers} % ------------------------------------------
Smart pointers are copiable, assignable and comparable. You can use them like
you would use normal ("raw") C++ pointers (eg. you can write
\lstinline{!ptr, ptr != NULL, ptr->method(), *ptr}...).
Type safety is also guaranteed, and you can type cast smart pointers using
the {\vcode staticCast()}, {\vcode dynamicCast()} and {\vcode constCast()}
equivalents on {\vcode mime::ref} and {\vcode vmime::weak\_ref} objects:
\begin{lstlisting}[caption={Casting smart pointers}]
class myBase : public vmime::object { }
class myObject : public myBase { }
vmime::ref <myObject> obj = vmime::create <myObject>();
// Implicit downcast
vmime::ref <myBase> base = obj;
// Explicit upcast
vmime::ref <myObject> obj2 = base.dynamicCast <myObject>();
\end{lstlisting}
Weak references are used to resolve reference cycles (an object which refers
directly or indirectly to itself). The following example illustrates a
typical problem of reference counting:
\begin{lstlisting}
class parent : public vmime::object
{
public:
void createChild(vmime::ref <child> c)
{
m_child = c;
}
private:
vmime::ref <child> m_child;
};
class child : public vmime::object
{
public:
child(vmime::ref <parent> p)
: m_parent(p)
{
}
private:
vmime::ref <parent> m_parent;
};
int main()
{
vmime::ref <parent> p = vmime::create <parent>();
vmime::ref <child> c = vmime::create <child>();
p->setChild(c);
}
\end{lstlisting}
In this example, neither {\vcode p} nor {\vcode c} will be deleted when
exiting {\vcode main()}. That's because {\vcode p} indirectly points to itself
{\em via} {\vcode c}, and {\em vice versa}. The solution is to use a weak
reference to the parent:
\begin{lstlisting}
vmime::weak_ref <parent> m_parent;
\end{lstlisting}
The decision to make the parent or the child a weak reference is purely
semantic, and it depends on the context and the relationships between the
objects. Note that when the parent is deleted, the {\vcode m\_parent} member
of the child points to \vnull.
More information about reference counting can be found on
Wikipedia\footnote{http://en.wikipedia.org/wiki/Reference\_counting}.
% ============================================================================
\section{Error handling}
In VMime, error handling is exclusively based on exceptions, there is no error
codes, or things like that.
VMime code may throw exceptions in many different situations: an unexpected
error occured, an operation is not supported, etc. You should catch them if
you want to report failures to the user. This is also useful when debugging
your program.
VMime exceptions support chaining: an exception can be encapsulated into
another exception to hide implementation details. The function
{\vcode exception::other()} returns the next exception in the chain,
or \vnull.
Following is an example code for catching VMime exceptions and writing error
messages to the console:
\begin{lstlisting}[caption={Catching VMime exceptions}]
std::ostream& operator<<(std::ostream& os, const vmime::exception& e)
{
os << "* vmime::exceptions::" << e.name() << std::endl;
os << " what = " << e.what() << std::endl;
// Recursively print all encapsuled exceptions
if (e.other() != NULL)
os << *e.other();
return os;
}
...
try
{
// ...some call to VMime...
}
catch (vmime::exception& e)
{
std::cerr << e; // VMime exception
}
catch (std::exception& e)
{
std::cerr << e.what(); // standard exception
}
\end{lstlisting}
Read the source of {\vexample example6} if yo want to see a more complete
example of using VMime exceptions (such as getting more detailed information
by using specialized classes of {\vcode vmime::exception}).
% ============================================================================
\section{Basic objects}
\subsection{The {\vcode component} class} % ----------------------------------
In VMime, all the components of a message inherit from the same class
{\vcode component}. This includes the message itself (classes {\vcode message}
and {\vcode bodyPart}), the header, the header fields and the value of each
header field, the body and all the parts in the message.
The class component provide a common interface for parsing or generating all
these components (methods {\vcode parse()} and {\vcode generate()}). It also
provides additional functions to get some information about the parsing
process or the structure (methods {\vcode getParsedOffset()},
{\vcode getParsedLength()} and {\vcode getChildComponents()}).
Vmime also provides a set of classes corresponding to the basic types found
in a message; for example a mailbox, a mailbox list, date/time information,
media type, etc. They all inherit from {\vcode component} too.
\subsection{Date and time} % -------------------------------------------------
Date and time are used in several places in VMime, particularly in header
fields (Date, Received, ...). VMime fully supports RFC-2822's date and time
specification. The object {\vcode vmime::datetime} is used to manipulate date
and time information, and to parse/generate it from/to RFC-2822 format.
The following code snippet show various manners of using the
{\vcode vmime::datetime} object:
\begin{lstlisting}[caption={Using {\vcode vmime::datetime} object}]
// Creating from string in RFC-2822 format
vmime::datetime d1("Sat, 08 Oct 2005 14:07:52 +0200");
// Creating from components
vmime::datetime d2(
/* date */ 2005, vmime::datetime::OCTOBER, 8,
/* time */ 14, 7, 52,
/* zone */ vmime::datetime::GMT2);
// Getting day of week
const int dow = d2.getWeekDay(); // 'dow' should be datetime::SATURDAY
\end{lstlisting}
\subsection{Media type} % ----------------------------------------------------
In MIME, the nature of the data contained in parts is identified using a
media type. A general type (eg. \emph{image}) and a sub-type (eg. \emph{jpeg})
are put together to form a media type (eg. \emph{image/jpeg}). This is also
called the MIME type.
There are a lot of media types officially registered, and vendor-specific
types are possible (they start with ``x-'', eg.
\emph{application/x-zip-compressed}).
In VMime, the object {\vcode vmime::mediaType} represents a media type. There
are also some constants for top-level types and sub-types in the
{\vcode vmime::mediaTypes} namespace. For example, you can instanciate a new
media type with:
\begin{lstlisting}
vmime::mediaType theType(
/* top-level type */ vmime::mediaTypes::IMAGE,
/* sub-type */ vmime::mediaTypes::IMAGE_JPEG);
// theType.getType() is "image"
// theType.getSubType() is "jpeg"
// theType.generate() returns "image/jpeg"
\end{lstlisting}
For more information about media types, see
RFC-2046\footnote{http://www.faqs.org/rfcs/rfc2046.html}.
\subsection{Mailbox and mailbox groups} % ------------------------------------
VMime provides several objects for working with mailboxes and addresses.
The {\vcode vmime::address} class is an abstract type for representing an
address: it can be either a mailbox (type {\vcode vmime::mailbox}) or a
mailbox group (type {\vcode vmime::mailboxGroup}). A mailbox is composed of
an email address (mandatory) and possibly a name. A mailbox group is simply
a named list of mailboxes (see Figure \ref{uml_addr_mbox_mboxgroup}).
\begin{lstlisting}[caption={Using mailboxes and mailbox groups}]
vmime::ref <vmime::mailbox> mbox1 = vmime::create <vmime::mailbox>
(/* name */ vmime::text("John Doe"), /* email */ "john.doe@acme.com");
vmime::ref <vmime::mailbox> mbox2 = vmime::create <vmime::mailbox>
(/* no name, email only */ "bill@acme.com");
vmime::ref <vmime::mailboxGroup> grp = vmime::create <vmime::mailboxGroup>();
grp->appendMailbox(mbox1);
grp->appendMailbox(mbox2);
\end{lstlisting}
\begin{figure}[ht!]
\center\includegraphics[width=0.7\textwidth]
{images/address-mailbox-mailboxgroup.png}
\caption{Diagram for address-related classes}
\label{uml_addr_mbox_mboxgroup}
\end{figure}
% ============================================================================
\section{Message, body parts and header}
\subsection{Introduction to MIME messages} % ---------------------------------
A MIME message is a recursive structure in which each part can contains one
or more parts (or \emph{entities}). Each part is composed of a header and
a body (actual contents). Figure \ref{uml_msg_body_header} shows how this
model is implemented in VMime, and all classes that take part in it.
\begin{figure}
\center\includegraphics[width=1.0\textwidth]
{images/message-body-header.png}
\caption{Overall structure of MIME messages}
\label{uml_msg_body_header}
\end{figure}
\subsection{Header and header fields} % --------------------------------------
\subsubsection{Standard header fields} % .....................................
Header fields carry information about a message (or a part) and its contents.
Each header field has a name and a value. All types that can be used as a
field value inherit from the {\vcode headerFieldValue} class.
You cannot instanciate header fields directly using their constructor.
Instead, you should use the {\vcode headerFieldFactory} object. This ensures
the right field type and value type is used for the specified field name.
For more information about how to use header fields and the factory, see
section \ref{msg-building-simple-message}.
Some standard fields are officially registered and have their value type
specified in a RFC. Table \ref{standard-fields} lists all the fields
registered by default in VMime and the value type they contains.
By default, all unregistered fields have a value of type {\vcode text}.
\begin{table}[!ht]
\begin{center}
\noindent\begin{tabularx}{0.85\textwidth}{|X|X|}
\hline
{\bf Field Name} &
{\bf Value Type} \\
\hline
\hline
From & mailbox \\
To & addressList \\
Cc & addressList \\
Bcc & addressList \\
Sender & mailbox \\
Date & datetime \\
Received & relay \\
Subject & text \\
Reply-To & mailbox \\
Delivered-To & mailbox \\
Organization & text \\
Return-Path & path \\
Mime-Version & text \\
Content-Type & mediaType \\
Content-Transfer-Encoding & encoding \\
Content-Description & text \\
Content-Disposition & contentDisposition \\
Content-Id & messageId \\
Content-Location & text \\
Message-Id & messageId \\
In-Reply-To & messageIdSequence \\
References & messageIdSequence \\
Original-Message-Id & messageId \\
Disposition & disposition \\
Disposition-Notification-To & mailboxList \\
\hline
\end{tabularx}
\end{center}
\label{standard-fields}
\caption{Standard fields and their types}
\end{table}
\subsubsection{Parameterized fields} % .......................................
In addition to a value, some header fields can contain one or more
\emph{name=value} couples which are called \emph{parameters}. For example,
this is used in the \emph{Content-Type} field to give more information about
the content:
\begin{verbatim}
Content-Type: text/plain; charset="utf-8"
\end{verbatim}
Fields that support parameters inherit from the
{\vcode parameterizedHeaderField} class which provides methods to deal with
these parameters: {\vcode appendParameter()}, {\vcode getParameterAt()}...
A parameter is identified by a name (eg. \emph{charset}) and associated to
a value of type {\vcode vmime::text}. Parameters provide helper functions to
convert automatically from basic types to text, and \emph{vice versa}. The
following example illustrates it:
\begin{lstlisting}[caption={Getting and setting parameter value in fields}]
vmime::ref <vmime::parameterizedField> field =
header->findField("X-Field-That-Contains-Parameters")
.dynamicCast <vmime::parameterizedField>();
// Use setValue() to convert from a basic type to 'text'
vmime::ref <vmime::parameter> prm = field->getParameter("my-date-param");
prm->setValue(vmime::datetime::now());
// Use getValueAs() to convert from 'text' to a basic type
prm = field->getParameter("my-charset-param");
const vmime::charset ch = prm->getValueAs <vmime::charset>();
\end{lstlisting}
Some fields provide easy access to their standard parameters (see
Table \ref{standard-prm-fields}). This avoids finding the parameter and
\emph{dynamic-casting} its value to the right type. The following code
illustrates how to use it:
\begin{lstlisting}
vmime::ref <vmime::contentTypeField> field =
header->getField(vmime::fields::CONTENT_TYPE)
.dynamicCast <vmime::contentTypeField>();
// 1. First solution: the "hard" way
vmime::ref <vmime::parameter> prm = field->findParameter("charset");
const charset ch1 = prm->getValueAs <vmime::charset>();
// 2. Second solution: the simple way
const charset ch2 = field->getCharset();
\end{lstlisting}
\vnote{In both cases, an exception {\vcode no\_such\_parameter} can be
thrown if the parameter does not exist, so be sure to catch it.}
\begin{table}[ht!]
\begin{center}
\noindent\begin{tabularx}{0.85\textwidth}{|l|l|X|}
\hline
{\bf Field Name} &
{\bf Field Type} &
{\bf Parameters} \\
\hline
\hline
Content-Type & contentTypeField & boundary, charset, report-type \\
\hline
Content-Disposition & contentDispositionField & creation-date,
modification-date, read-date, filename, size \\
\hline
\end{tabularx}
\end{center}
\label{standard-prm-fields}
\caption{Standard parameterized fields}
\end{table}
% ============================================================================
\section{Streams}
\subsection{Streams and stream adapters} % -----------------------------------
Streams permit reading or writing data whatever the underlying system is:
a file on a hard disk, a socket connected to a remote service...
There are two types of streams: input streams (from which you can read data)
and output streams (in which you can write data). Some adapters are provided
for compatibility and convenience, for example:
\begin{itemize}
\item {\vcode inputStreamAdapter} and {\vcode outputStreamAdapter}: allow
to use standard C++ iostreams with VMime;
\item {\vcode inputStreamStringAdapter} and
{\vcode outputStreamStringAdapter}: use a {\vcode vmime::string} object to
read/write data.
\end{itemize}
The following example shows two ways of writing the current date to the
standard output, using stream adapters:
\begin{lstlisting}[caption={Using stream adapters}]
// Get current date and time
const vmime::datetime date = vmime::datetime::now();
// 1. Using outputStreamAdapter
vmime::utility::outputStreamAdapter out(std::cout);
std::cout << "Current date is: ";
date.generate(out);
std::cout << std::endl;
// 2. Using outputStreamStringAdapter
vmime::string dateStr;
vmime::utility::outputStreamStringAdapter outStr(dateStr);
std::cout << "Current date is: " << dateStr << std::endl;
\end{lstlisting}
\subsection{Stream filters} % ------------------------------------------------
Input and output streams can be filtered to perform inline conversions (for
example, there is a filter to convert ``{\textbackslash}r{\textbackslash}n''
sequences to ``{\textbackslash}n''). They inherit from
{\vcode vmime::utility::filteredInputStream} or
{\vcode vmime::utility::filteredOutputStream} and are used like adapters (some
filters also accept parameters; read the documentation).
The most useful filter in VMime (and probably the only one you will need) is
the {\vcode charsetFilteredOutputStream}, which performs inline conversion
of charsets. See \ref{section_charsets} to know how to use it.
\vnote{After you have finished to use a filtered output stream, it is
important to call {\vcode flush()} on it to flush the internal buffer.
If {\vcode flush()} is not called, not all data may be written to the
underlying stream.}
% ============================================================================
\section{Content handlers}
\subsection{Introduction} % --------------------------------------------------
Content handlers are an abstraction for data sources. They are currently used
when some data need to be stored for later use (eg. body part contents,
attachment data, ...). Data can be stored encoded or unencoded (for more
information about encodings, see \ref{section_encodings}).
\subsection{Extracting data from content handlers} % -------------------------
You can extract data in a content handler using the {\vcode extract()} method
(which automatically decodes data if encoded) or {\vcode extractRaw()} (which
extracts data without perfoming any decoding).
The following example shows how to extract the body text from a message, and
writing it to the standard output with charset conversion:
\begin{lstlisting}[caption={Using content handlers to extract body text from
a message}]
// Suppose we already have a message
vmime::ref <vmime::message> msg;
// Obtains a reference to the body contents
vmime::ref <vmime::body> body = msg->getBody();
vmime::ref <vmime::contentHandler> cts = msg->getContents();
vmime::utility::outputStreamAdapter out(std::cout);
cts->extract(out);
\end{lstlisting}
\vnote{The body contents is extracted ``as is''. No charset conversion is
performed. See \ref{section_charsets} to know more about conversion between
charsets.}
\subsection{Creating content handlers} % -------------------------------------
When you are building a message, you may need to instanciate content handlers
if you want to set the contents of a body part. The following code snippet
shows how to set the body text of a part from a string:
\begin{lstlisting}[caption={Setting the contents of a body part}]
vmime::ref <vmime::bodyPart> part; // suppose we have a body part
// Create a new content handler from a string
vmime::ref <vmime::contentHandler> cth =
vmime::create <vmime::stringContentHandler>("Put body contents here");
// Set the contents
part->getBody()->setContents(cth);
\end{lstlisting}
Content handlers are also used when creating attachments. The following
example illustrates how to create an attachment from a file:
\begin{lstlisting}[caption={Creating an attachment from a file}]
// Create a stream from a file
std::ifstream* fileStream = new std::ifstream();
fileStream->open("/home/vincent/paris.jpg", std::ios::binary);
if (!*fileStream)
// handle error
vmime::ref <utility::stream> dataStream =
vmime::create <vmime::utility::inputStreamPointerAdapter>(fileStream);
// NOTE: 'fileStream' will be automatically deleted
// when 'dataStream' is deleted
// Create a new content handler
vmime::ref <contentHandler> data =
vmime::create <vmime::streamContentHandler>(dataStream, 0);
// Now create the attachment
ref <vmime::attachment> att = vmime::create <vmime::defaultAttachment>
(
/* attachment data */ data,
/* content type */ vmime::mediaType("image/jpeg"),
/* description */ vmime::text("Holiday photo"),
/* filename */ vmime::word("paris.jpg")
);
\end{lstlisting}
You will see later that the {\vcode vmime::fileAttachment} class already
encapsulates all the mechanics to create an attachment from a file.
% ============================================================================
\section{Character sets, charsets and conversions\label{section_charsets}}
Quoting from RFC-2278: \emph{`` The term 'charset' is used to refer to a
method of converting a sequence of octets into a sequence of characters.''}
With the {\vcode vmime::charset} object, VMime supports conversion between
charsets using the {\em iconv} library, which is available on almost all
existing platforms. See {\vcode vmime::charset} and
{\vcode vmime::charsetConverter} in the class documentation to know more
about charset conversion.
The following example shows how to convert data in one charset to another
charset. The data is extracted from the body of a message and converted
to UTF-8 charset:
\begin{lstlisting}[caption={Extracting and converting body contents to a
specified charset}]
vmime::ref <vmime::message> msg; // we have a message
// Obtain the content handler first
vmime::ref <vmime::body> body = msg->getBody();
vmime::ref <const vmime::contentHandler> cth = body->getContents();
// Then, extract and convert the contents
vmime::utility::outputStreamAdapter out(std::cout);
vmime::utility::charsetFilteredOutputStream fout
(/* source charset */ body->getCharset(),
/* dest charset */ vmime::charset("utf-8"),
/* dest stream */ out);
cth->extract(fout);
fout.flush(); // Very important!
\end{lstlisting}
% ============================================================================
\section{Non-ASCII text in header fields}
MIME standard defines methods\footnote{See RFC-2047: Message Header Extensions
for Non-ASCII Text} for dealing with data which is not 7-bit only (ie. the
ASCII character set), in particular in header fields. For example, the field
``Subject:'' use this data type.
VMime is fully compatible with RFC-2047 and provides two objects for
manipulating 8-bit data: {\vcode vmime::text} and {\vcode vmime::word}. A word
represents textual information encoded in a specified charset. A text is
composed of one or more words.
RFC-2047 describes the process of encoding 8-bit data into a 7-bit form;
basically, it relies on Base64 and Quoted-Printable encoding. Hopefully, all
the encoding/decoding process is done internally by VMime, so creating text
objects is fairly simple:
\begin{lstlisting}[caption={Creating \vcode{vmime::text} objects}]
vmime::string inText = "Linux dans un téléphone mobile";
vmime::charset inCharset = "utf-8";
vmime::text outText;
vmime::newFromString(inText, inCharset, &outText);
// 'outText' now contains 3 words:
// . <us-ascii> "Linux dans un "
// . <utf-8> "téléphone "
// . <us-ascii> "mobile"
vmime::ref <vmime::header> header = myMessage->getHeader();
header->Subject()->setValue(outText);
\end{lstlisting}
In general, you will not need to decode RFC-2047-encoded data as the process
is totally transparent in VMime. If you really have to, you can use the
{\vcode vmime::text::decodeAndUnfold()} static method to create a text object
from encoded data.
For example, say you have the following encoded data:
\begin{verbatim}
Linux dans un =?UTF-8?B?dMOpbMOpcGhvbmUgbW9iaWxl?=
\end{verbatim}
You can simply decode it using the following code:
\begin{lstlisting}[caption={Decoding RFC-2047-encoded data}]
vmime::string inData =
"Linux dans un =?UTF-8?B?dMOpbMOpcGhvbmUgbW9iaWxl?=";
vmime::text outText;
vmime::text::decodeAndUnfold(inData, &outText);
\end{lstlisting}
{\vcode vmime::text} also provides a function to convert all the words to
another charset in a single call. The following example shows how to convert
text stored in the Subject field of a message:
\begin{lstlisting}[caption={Converting data in a {\vcode vmime::text} to a
specified charset}]
vmime::ref <vmime::message> msg; // we have a message
vmime::text subject = msg->getHeader()->Subject()->getValue();
const vmime::string subjectText =
subject.getConvertedText(vmime::charset("utf-8"));
// 'subjectText' now contains the subject in UTF-8 encoding
\end{lstlisting}
% ============================================================================
\section{Encodings\label{section_encodings}}
\subsection{Introduction} % --------------------------------------------------
The MIME standard defines a certain number of encodings to allow data
to be safely transmitted from one peer to another. VMime provides
data encoding and decoding using the {\vcode vmime::encoder} object.
You should not need to use encoders directly, as all encoding/decoding
process is handled internally by the library, but it is good to know
they exist and how they work.
\subsection{Using encoders} % ------------------------------------------------
You can create an instance of an encoder using the 'vmime::encoderFactory'
object, giving the encoding name ({\it base64}, {\it quoted-printable}, ...).
The following example creates an instance of the Base64 encoder to encode
some data:
\begin{lstlisting}[caption={A simple example of using an encoder}]
vmime::ref <vmime::encoder> enc =
vmime::encoderFactory::getInstance()->create("base64");
vmime::string inString("Some data to encode");
vmime::utility::inputStreamStringAdapter in(inString);
vmime::string outString;
vmime::utility::outputStreamStringAdapter out(outString);
enc->encode(in, out);
std::cout << "Encoded data is:" << outString << std::endl;
\end{lstlisting}
\subsection{Enumerating available encoders} % --------------------------------
The behaviour of the encoders can be configured using properties. However,
not all encoders support properties. The following example\footnote{This is
an excerpt from {\vexample example6}} enumerates available encoders and the
supported properties for each of them:
\begin{lstlisting}[caption={Enumerating encoders and their properties}]
vmime::encoderFactory* ef = vmime::encoderFactory::getInstance();
std::cout << "Available encoders:" << std::endl;
for (int i = 0 ; i < ef->getEncoderCount() ; ++i)
{
// Output encoder name
vmime::ref <const vmime::encoderFactory::registeredEncoder>
enc = ef->getEncoderAt(i);
std::cout << " * " << enc->getName() << std::endl;
// Create an instance of the encoder to get its properties
vmime::ref <vmime::encoder> e = enc->create();
std::vector <vmime::string> props = e->getAvailableProperties();
std::vector <vmime::string>::const_iterator it;
for (it = props.begin() ; it != props.end() ; ++it)
std::cout << " - " << *it << std::endl;
\end{lstlisting}
% ============================================================================
\section{Progress listeners}
Progress listeners are used with objects that can notify you about the state
of progress when they are performing an operation.
The {\vcode vmime::utility::progressListener} interface is rather simple:
\begin{lstlisting}
const bool cancel() const;
void start(const int predictedTotal);
void progress(const int current, const int currentTotal);
void stop(const int total);
\end{lstlisting}
{\vcode start()} and {\vcode stop()} are called at the beginning and the end
of the operation, respectively. {\vcode progress()} is called each time the
status of progress changes (eg. a chunk of data has been processed). There is
no unit specified for the values passed in argument. It depends on the
notifier: it can be bytes, percent, number of messages...
Your listener can return {\vcode} in the {\vcode cancel()} method to cancel
the operation. However, be warned that cancelling is not always supported by
the source object.

100
doc/book/book.tex Normal file
View File

@ -0,0 +1,100 @@
\documentclass[11pt]{report}
\title{{\Huge VMime Book} \\ \ \\ A Developer's Guide To VMime}
\author{Vincent Richard \\ vincent@vincent-richard.net}
\usepackage{graphicx}
\usepackage{tabularx}
\usepackage{listings}
\usepackage[usenames]{color}
\usepackage{ucs}
\usepackage[latin1]{inputenc}
\usepackage[vcentering,dvips]{geometry}
%\usepackage{type1cm} % scalable Computer Modern fonts
\usepackage{courier} % use Adobe Courier instead of Computer Modern Typewriter
\usepackage{fancyheadings}
\usepackage{hyperref}
\usepackage{sverb}
\usepackage{footmisc}
\addtolength{\parskip}{+0.3cm}
\linespread{1.05}
\setlength{\skip\footins}{1cm} % margin between text and footnotes
\clubpenalty=1000
\widowpenalty=1000
\setcounter{secnumdepth}{10}
\setcounter{tocdepth}{10}
\def\vcode{\tt}
\def\vnull{{\tt NULL}}
\newcommand{\vnote}[1]{{\sc note:} #1}
\def\vexample{\tt\sc}
\newcommand{\verti}[1]{\rotatebox{90}{#1\ }} % vertical text
\def\vdot{$\bullet$}
\sloppy % Disable "overfull \hbox..." warnings
\newcommand{\Chapter}[1]{\chapter{#1} \setcounter{figure}{1}}
% 'geometry' configuration
\geometry{papersize={210mm,297mm},total={160mm,230mm}}
% 'listings' configuration
\definecolor{listingFrame}{rgb}{0.9,0.9,0.9}
\lstset{language=C++,showstringspaces=false}
\lstset{captionpos=b,extendedchars=true,inputencoding=latin1}
\lstset{fontadjust=true,basewidth={0.5em,0.4em},columns=fixed,flexiblecolumns=false}
\lstset{frame=leftline,framerule=0.1cm,framesep=0.3cm,rulecolor=\color{listingFrame}}
\lstset{abovecaptionskip=0.5cm,xleftmargin=1.1cm,aboveskip=0.5cm,belowskip=0.2cm}
% 'hyperref' configuration
\hypersetup{
backref=true,pagebackref=true,hyperindex=rue,colorlinks=true,
breaklinks=true,urlcolor=blue,linkcolor=black,bookmarks=true,bookmarksopen=true
}
\begin{document}
% Title page
\maketitle
\newpage
% Table of contents
\tableofcontents
\newpage
% Chapters
\include{intro}
\include{building}
\include{start}
\include{basics}
\include{msg}
\include{net}
\thispagestyle{empty}
\ \newpage
% List of listings
\lstlistoflistings
\addcontentsline{toc}{chapter}{Listings}
% List of figures
\listoffigures
\addcontentsline{toc}{chapter}{List of figures}
% List of table
\listoftables
\addcontentsline{toc}{chapter}{List of tables}
% Appendixes
\appendix
\chapter{The GNU General Public License\label{appendix_license}}
\verbinput{../../COPYING}
\end{document}

102
doc/book/building.tex Normal file
View File

@ -0,0 +1,102 @@
\chapter{Building and Installing VMime\label{chapter_building}}
% ============================================================================
\section{Introduction}
If no pre-build packages of VMime is available for your system, or if for some
reason you want to compile it yourself from scratch, this section will guide
you through the process.
% ============================================================================
\section{What you need}
To build VMime from the sources, you will need the following:
\begin{itemize}
\item a working C++ compiler with good STL implementation and also a good
support for templates (for example, \href{http://gcc.gnu.org/}{GNU GCC}) ;
\item \href{http://www.scons.org/}{SCons} build system, or the
autoconf/automake tool chain ;
\item an usable iconv() implementation (see
\href{http://www.gnu.org/software/libiconv/}{libiconv of GNU Project}) ;
\item the \href{http://www.gnu.org/software/gsasl/}{GNU SASL Library} if you
want SASL\footnote{Simple Authentication and Security Layer} support ;
\item the \href{http://www.gnu.org/software/gnutls/}{GNU TLS Library} if you
want SSL and TLS\footnote{Transport Layer Security} support ;
\end{itemize}
% ============================================================================
\section{Obtaining source files}
You can download a package containing the source files of the latest release
of the VMime library from the \href{http://www.vmime.org/}{VMime web site}.
You can also obtain the current development version from the CVS. VMime's CVS
repository can be checked out from anonymous CVS with the following
instructions. When prompted for a password for {\em anonymous}, simply press
Enter key.
\begin{verbatim}
cvs -d:pserver:anonymous@cvs.vmime.org:/cvsroot/vmime login
cvs -z3 -d:pserver:anonymous@cvs.vmime.org:/cvsroot/vmime co -P vmime
\end{verbatim}
% ============================================================================
\section{Compiling and installing}
There are two possibilities for compiling VMime: using SCons building system,
or using the Autotools.
\vnote{MS Visual C++ users, you can skip this section as a project file
is provided in the distribution tarball.}
SCons is only used for development purposes, and so it is recommended that you
use Autotools to build the project as it is a more portable solution, and is
likely to work out-of-the-box on your computer. Thus, we will not describe
the process of compiling VMime using SCons here.
\vnote{Windows users, you can use MinGW and MSYS\footnote{See on the MinGW
website: http://www.mingw.org/} to install a POSIX compatible environment
on top of Windows. This allow executing configure scripts and Makefiles on
Windows}.
Before compiling VMime, you should run the {\vcode configure} script to
detect some parameters specific to your platform. Go into the directory where
you extracted the tarball and type:
\begin{verbatim}
$ ./configure
\end{verbatim}
This will create a file named {\vcode config.hpp} in the {\vcode vmime/}
directory, with the parameters detected for your platform. You should modify
this file only if you know what you are doing!
If you want to enable or disable some features in VMime, you can obtain some
help by typing {\vcode ./configure --help}. The defaults should be OK though.
Next, you can start the compilation process:
\begin{verbatim}
$ make
\end{verbatim}
Please wait a few minutes will the compilation runs (you should have some time
to have a coffee right now!). If you get errors during the compilation, be
sure your system meet the requirements given at the beginning of the chapter.
You can also try to get a newer version (from the CVS, for example) or to
get some help on VMime user forums.
If everything has been compiled successfully, you can install the library and
the development files on your system:
\begin{verbatim}
# make install
\end{verbatim}
\vnote{you must do that with superuser rights (root) if you chose to install
the library into the default location (ie: /usr/lib and /usr/include).}
Now, you are done! You can jump to the next chapter to know how to use VMime
in your program...

14
doc/book/images/Makefile Normal file
View File

@ -0,0 +1,14 @@
# 'inkscape' is needed for converting from SVG to PNG
build-makefile:
@echo "# Auto-generated file" > Makefile2
@echo ".SUFFIXES: .png .svg" >> Makefile2
@echo -n "foo: " >> Makefile2
@for f in *.svg ; do (echo -n " $$f" | sed 's/svg/png/g') >> Makefile2 ; done
@echo >> Makefile2
@echo " @echo -n" >> Makefile2
@echo ".svg.png:" >> Makefile2
@echo ' echo Converting $$<' >> Makefile2
@echo ' inkscape -b "#ffffff" -w 1000 -e $$@ $$<' >> Makefile2
@make -f Makefile2

View File

@ -0,0 +1,355 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="453.27998pt"
height="307.89001pt"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.42.2"
sodipodi:docbase="/home/vincent/projects/vmime/doc/book/images"
sodipodi:docname="address-mailbox-mailboxgroup.svg"
inkscape:export-xdpi="73.779999"
inkscape:export-ydpi="73.779999">
<defs
id="defs3">
<marker
inkscape:stockid="Torso"
orient="auto"
refY="0.0"
refX="0.0"
id="Torso"
style="overflow:visible">
<g
id="g2045"
transform="scale(0.7)">
<path
sodipodi:nodetypes="ccccc"
id="path1128"
d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none" />
<path
sodipodi:nodetypes="cc"
id="path1909"
d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none" />
<path
sodipodi:nodetypes="cc"
id="path1910"
d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none" />
<rect
transform="matrix(0.527536,-0.849533,0.887668,0.460484,0.000000,0.000000)"
y="-1.7408575"
x="-10.391706"
height="2.7608147"
width="2.6366582"
id="rect2035"
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
<rect
transform="matrix(0.671205,-0.741272,0.790802,0.612072,0.000000,0.000000)"
y="-7.9629307"
x="4.9587269"
height="2.8614161"
width="2.7327356"
id="rect2036"
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
<path
transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,25.96648,19.71619)"
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
sodipodi:ry="0.60731727"
sodipodi:rx="0.60731727"
sodipodi:cy="-28.685045"
sodipodi:cx="16.172634"
id="path2037"
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
sodipodi:type="arc" />
<path
transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,26.82450,16.99126)"
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
sodipodi:ry="0.60731727"
sodipodi:rx="0.60731727"
sodipodi:cy="-28.685045"
sodipodi:cx="16.172634"
id="path2038"
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
sodipodi:type="arc" />
</g>
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0.0"
refX="0.0"
id="TriangleOutL"
style="overflow:visible">
<path
sodipodi:nodetypes="cccc"
id="path5324"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
transform="scale(0.8)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1.0000000"
inkscape:pageshadow="2"
inkscape:zoom="1.0000000"
inkscape:cx="248.49444"
inkscape:cy="298.91345"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="1150"
inkscape:window-height="986"
inkscape:window-x="0"
inkscape:window-y="30"
fill="#ff0000"
inkscape:showpageshadow="true"
showguides="true"
showgrid="false"
inkscape:grid-bbox="false"
inkscape:grid-points="false" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<path
id="path5442"
d="M 303.65293,104.37647 L 303.65293,173.68448"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5440"
d="M 462.39333,172.39335 L 462.39333,240.10630"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5438"
d="M 139.24323,172.39335 L 139.24323,240.10630"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
d="M 257.32713,293.92642 L 392.05898,293.92642"
id="path2543" />
<rect
style="fill:#e0f5cc;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect1291"
width="132.69368"
height="105.95705"
x="237.85556"
y="13.003311" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="245.51651"
y="55.887268"
id="text1293"
sodipodi:linespacing="125.00000%"><tspan
sodipodi:role="line"
id="tspan2242"
x="245.51651"
y="55.887268">isEmpty() : bool</tspan><tspan
sodipodi:role="line"
id="tspan2244"
x="245.51651"
y="70.887268">isGroup() : bool</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="279.65814"
y="29.038483"
id="text2347"
sodipodi:linespacing="125.00000%"><tspan
sodipodi:role="line"
id="tspan2222"
x="279.65814"
y="29.038483">address</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
d="M 238.27499,37.373470 L 370.37704,37.373470"
id="path2351" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2433"
width="242.87289"
height="157.12062"
x="17.947495"
y="215.62213" />
<text
xml:space="preserve"
style="font-size:12.000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="24.265694"
y="258.30316"
id="text2435"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan2315"
x="24.265694"
y="258.30316">getName() : string</tspan><tspan
sodipodi:role="line"
id="tspan2317"
x="24.265694"
y="273.30316">setName(n : string) : void</tspan><tspan
sodipodi:role="line"
id="tspan2319"
x="24.265694"
y="288.30316">appendMailbox(m : ref &lt;mailbox&gt;)</tspan><tspan
sodipodi:role="line"
id="tspan2321"
x="24.265694"
y="303.30316">getMailboxCount() : int</tspan><tspan
sodipodi:role="line"
id="tspan2323"
x="24.265694"
y="318.30316">getMailboxAt(i : int) : ref &lt;mailbox&gt;</tspan><tspan
sodipodi:role="line"
id="tspan2325"
x="24.265694"
y="333.30316">...</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="91.950951"
y="231.45441"
id="text2439"
sodipodi:linespacing="125.00000%"><tspan
sodipodi:role="line"
id="tspan2246"
x="91.950951"
y="231.45441">mailboxGroup</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
d="M 19.330207,239.78939 L 260.20091,239.78939"
id="path2443" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2447"
width="174.79645"
height="124.30678"
x="373.27942"
y="215.33472" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="380.74768"
y="258.15143"
id="text2449"
sodipodi:linespacing="125.00000%"><tspan
sodipodi:role="line"
id="tspan2286"
x="380.74768"
y="258.15143">getName() : text</tspan><tspan
sodipodi:role="line"
id="tspan2288"
x="380.74768"
y="273.15143">setName(n : text) : void</tspan><tspan
sodipodi:role="line"
id="tspan2290"
x="380.74768"
y="288.15143">getEmail() : string</tspan><tspan
sodipodi:role="line"
id="tspan2292"
x="380.74768"
y="303.15143">setEmail(e : string) : void</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="434.7478"
y="231.30267"
id="text2453"
sodipodi:linespacing="125.00000%"><tspan
sodipodi:role="line"
id="tspan2276"
x="434.74780"
y="231.30267">mailbox</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 373.64397,239.63760 L 547.69600,239.63760"
id="path2457" />
<rect
style="fill:#ffffff;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500457;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2541"
width="15.541327"
height="15.541327"
x="-23.443876"
y="392.33624"
transform="matrix(0.707107,-0.707107,0.707107,0.707107,0.000000,0.000000)" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="344.41357"
y="289.23822"
id="text2545"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5160"
sodipodi:role="line"
y="289.23822"
x="344.41357">0..n</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="293.07501"
y="312.23822"
id="text2549"
sodipodi:linespacing="125.00000%"><tspan
sodipodi:role="line"
id="tspan2294"
x="293.07501"
y="312.23822">mailboxes</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="289.07501"
y="289.23822"
id="text2553"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5158"
sodipodi:role="line"
y="289.23822"
x="289.07501">0</tspan></text>
<path
id="path2575"
d="M 290.22642,134.62157 L 318.11534,134.62157 L 303.70606,120.21230 L 290.22642,134.62157 z "
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
</g>
<path
id="path5436"
d="M 139.78693,173.17443 L 461.72537,173.17443"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;stroke-dasharray:none" />
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,716 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="707.28000pt"
height="612.89000pt"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.42.2"
sodipodi:docbase="/home/vincent/projects/vmime/doc/book/images"
sodipodi:docname="message-body-header.svg"
inkscape:export-xdpi="73.779999"
inkscape:export-ydpi="73.779999">
<defs
id="defs3">
<marker
inkscape:stockid="Torso"
orient="auto"
refY="0.0"
refX="0.0"
id="Torso"
style="overflow:visible">
<g
id="g2045"
transform="scale(0.7)">
<path
sodipodi:nodetypes="ccccc"
id="path1128"
d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none" />
<path
sodipodi:nodetypes="cc"
id="path1909"
d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none" />
<path
sodipodi:nodetypes="cc"
id="path1910"
d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none" />
<rect
transform="matrix(0.527536,-0.849533,0.887668,0.460484,0.000000,0.000000)"
y="-1.7408575"
x="-10.391706"
height="2.7608147"
width="2.6366582"
id="rect2035"
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
<rect
transform="matrix(0.671205,-0.741272,0.790802,0.612072,0.000000,0.000000)"
y="-7.9629307"
x="4.9587269"
height="2.8614161"
width="2.7327356"
id="rect2036"
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
<path
transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,25.96648,19.71619)"
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
sodipodi:ry="0.60731727"
sodipodi:rx="0.60731727"
sodipodi:cy="-28.685045"
sodipodi:cx="16.172634"
id="path2037"
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
sodipodi:type="arc" />
<path
transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,26.82450,16.99126)"
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
sodipodi:ry="0.60731727"
sodipodi:rx="0.60731727"
sodipodi:cy="-28.685045"
sodipodi:cx="16.172634"
id="path2038"
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
sodipodi:type="arc" />
</g>
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0.0"
refX="0.0"
id="TriangleOutL"
style="overflow:visible">
<path
sodipodi:nodetypes="cccc"
id="path5324"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
transform="scale(0.8)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.00000000"
inkscape:cx="394.46478"
inkscape:cy="380.70648"
inkscape:document-units="px"
inkscape:current-layer="svg2"
inkscape:window-width="1150"
inkscape:window-height="986"
inkscape:window-x="0"
inkscape:window-y="30" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<path
id="path2407"
d="M 253.02743,136.68448 L 253.02743,67.376470"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5442"
d="M 635.99153,281.37647 L 635.99153,350.68448"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5440"
d="M 783.39333,349.39335 L 783.39333,417.10630"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5438"
d="M 446.06998,349.39335 L 446.06998,417.10630"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 16.987518,219.56412 L 153.50367,219.56412"
id="path2375" />
<path
id="path2345"
d="M 508.29892,263.82217 L 105.85472,471.31117"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path2347"
d="M 502.39025,252.30315 L 515.17042,277.09145 L 521.37461,257.68108 L 502.39025,252.30315 z "
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<g
transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,533.0981,623.6004)"
id="g2321">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M -100.36367,371.67294 L 26.017722,371.67294"
id="path2323" />
<g
id="g2325"
transform="translate(-113.9177,-82.19766)">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 140.20049,454.12696 L 129.75724,443.68372"
id="path2327" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 139.84823,453.80527 L 129.66343,463.99007"
id="path2329" />
</g>
</g>
<path
id="path2241"
d="M 507.60723,180.01568 L 350.16119,180.01568"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<rect
style="fill:#dcf5e6;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect1291"
width="236.14607"
height="157.54773"
x="522.13733"
y="126.86942" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="529.52441"
y="169.54865"
id="text1293"
sodipodi:linespacing="120.00000%"><tspan
id="tspan5228"
sodipodi:role="line"
y="169.54865"
x="529.52441">parse(buf : string) : void</tspan><tspan
id="tspan5230"
sodipodi:role="line"
y="183.94865"
x="529.52441">generate(out : outputStream) : void</tspan><tspan
id="tspan5232"
sodipodi:role="line"
y="198.34865"
x="529.52441" /><tspan
id="tspan5234"
sodipodi:role="line"
y="212.74865"
x="529.52441">clone() : ref &lt;component&gt;</tspan><tspan
id="tspan5236"
sodipodi:role="line"
y="227.14865"
x="529.52441">copyFrom(src : component) : void</tspan><tspan
id="tspan5238"
sodipodi:role="line"
y="241.54865"
x="529.52441">getChildComponents() : vector</tspan><tspan
id="tspan5240"
sodipodi:role="line"
y="255.94865"
x="529.52441">getParsedOffset() : int</tspan><tspan
id="tspan5242"
sodipodi:role="line"
y="270.34865"
x="529.52441">getParsedLength() : int</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="609.02057"
y="142.69992"
id="text2347"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5172"
sodipodi:role="line"
y="142.69992"
x="609.02057">component</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 522.50261,151.03487 L 758.16522,151.03487"
id="path2351" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2353"
width="218.71376"
height="151.16983"
x="145.51056"
y="133.04831" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="154.6483"
y="175.75391"
id="text2355"
sodipodi:linespacing="120.00000%"><tspan
id="tspan2349"
sodipodi:role="line"
y="175.75391"
x="154.64830">getBody() : ref &lt;body&gt;</tspan><tspan
id="tspan2351"
sodipodi:role="line"
y="190.15391"
x="154.64830">getHeader() : ref &lt;header&gt;</tspan><tspan
id="tspan2353"
sodipodi:role="line"
y="204.55391"
x="154.64830">getParentPart() : ref &lt;bodyPart&gt;</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="222.66418"
y="148.90518"
id="text2375"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5272"
sodipodi:role="line"
y="148.90518"
x="222.66418">bodyPart</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 145.87565,157.24013 L 363.84409,157.24013"
id="path2379" />
<g
transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,548.9327,384.9312)"
id="g2247">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M -100.36367,371.67294 L 26.017722,371.67294"
id="path2387" />
<g
id="g2395"
transform="translate(-113.9177,-82.19766)">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 140.20049,454.12696 L 129.75724,443.68372"
id="path2389" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 139.84823,453.80527 L 129.66343,463.99007"
id="path2393" />
</g>
</g>
<text
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="138.11696"
y="382.06345"
id="text2403"><tspan
id="tspan2273"
sodipodi:role="line"
y="382.06345"
x="138.11696">body</tspan></text>
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2433"
width="276.37778"
height="157.12062"
x="304.96820"
y="412.46472" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="313.24988"
y="455.14575"
id="text2435"
sodipodi:linespacing="120.00000%"><tspan
id="tspan5256"
sodipodi:role="line"
y="455.14575"
x="313.24988">hasField(name : string) : bool</tspan><tspan
id="tspan5258"
sodipodi:role="line"
y="469.54575"
x="313.24988">findField(name : string) : ref &lt;headerField&gt;</tspan><tspan
id="tspan5260"
sodipodi:role="line"
y="483.94575"
x="313.24988">findAllFields(name : string) : vector</tspan><tspan
id="tspan5262"
sodipodi:role="line"
y="498.34575"
x="313.24988">getField(name : string) : ref &lt;headerField&gt;</tspan><tspan
id="tspan5264"
sodipodi:role="line"
y="512.74575"
x="313.24988">appendField(f : ref &lt;headerField&gt;) : void</tspan><tspan
id="tspan5266"
sodipodi:role="line"
y="527.14575"
x="313.24988">...</tspan><tspan
id="tspan5268"
sodipodi:role="line"
y="541.54576"
x="313.24988">getFieldAt(pos : int) : ref &lt;headerField&gt;</tspan><tspan
id="tspan5270"
sodipodi:role="line"
y="555.94576"
x="313.24988">getFieldCount() : int</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="412.95099"
y="428.297"
id="text2439"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5154"
sodipodi:role="line"
y="428.29700"
x="412.95099">header</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 306.34976,436.63194 L 580.95005,436.63194"
id="path2443" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2447"
width="174.79645"
height="124.30678"
x="694.27942"
y="412.17731" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="701.74768"
y="454.99402"
id="text2449"
sodipodi:linespacing="120.00000%"><tspan
id="tspan5176"
sodipodi:role="line"
y="454.99402"
x="701.74768">getName() : string</tspan><tspan
id="tspan5178"
sodipodi:role="line"
y="469.39402"
x="701.74768">getValue() : component</tspan><tspan
id="tspan5180"
sodipodi:role="line"
y="483.79402"
x="701.74768">setValue(val : component)</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="738.73987"
y="428.14526"
id="text2453"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5152"
sodipodi:role="line"
y="428.14526"
x="738.73987">headerField</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 694.64397,436.48015 L 868.69600,436.48015"
id="path2457" />
<rect
style="fill:#ffffff;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500381;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2541"
width="15.541226"
height="15.541226"
x="65.401291"
y="759.55469"
transform="matrix(0.707107,-0.707107,0.707107,0.707107,0.000000,0.000000)" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 605.07226,490.76897 L 694.31385,490.76897"
id="path2543" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="661.23236"
y="486.08081"
id="text2545"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5160"
sodipodi:role="line"
y="486.08081"
x="661.23236">0..n</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="626.90173"
y="509.08081"
id="text2549"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5156"
sodipodi:role="line"
y="509.08081"
x="626.90173">fields</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="611.56311"
y="486.08081"
id="text2553"
sodipodi:linespacing="100.00000%"><tspan
id="tspan5158"
sodipodi:role="line"
y="486.08081"
x="611.56311">0</tspan></text>
<path
id="path2575"
d="M 622.56502,300.28297 L 650.45394,300.28297 L 636.04466,285.87370 L 622.56502,300.28297 z "
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2225"
width="171.85686"
height="151.16983"
x="74.698677"
y="412.04831" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="82.183701"
y="454.75391"
id="text2227"
sodipodi:linespacing="120.00000%"><tspan
id="tspan2377"
sodipodi:role="line"
y="454.75391"
x="82.183701">getContents() : ref &lt;ch&gt;</tspan><tspan
id="tspan2379"
sodipodi:role="line"
y="469.15391"
x="82.183701">getCharset() : charset</tspan><tspan
id="tspan2381"
sodipodi:role="line"
y="483.55391"
x="82.183701">getEncoding() : encoding</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="141.69556"
y="427.90518"
id="text2231"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2237"
sodipodi:role="line"
y="427.90518"
x="141.69556">body</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 75.063282,436.24013 L 246.17599,436.24013"
id="path2235" />
<path
id="path2239"
d="M 506.13949,167.78737 L 506.13949,195.67630 L 520.54876,181.26702 L 506.13949,167.78737 z "
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<g
transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,548.9327,384.9312)"
id="g2253">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M -100.36367,371.67294 L 26.017722,371.67294"
id="path2255" />
<g
id="g2257"
transform="translate(-113.9177,-82.19766)">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 140.20049,454.12696 L 129.75724,443.68372"
id="path2259" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 139.84823,453.80527 L 129.66343,463.99007"
id="path2261" />
</g>
</g>
<g
transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,704.8357,384.9312)"
id="g2263">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M -100.36367,371.67294 L 26.017722,371.67294"
id="path2265" />
<g
id="g2267"
transform="translate(-113.9177,-82.19766)">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 140.20049,454.12696 L 129.75724,443.68372"
id="path2269" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 139.84823,453.80527 L 129.66343,463.99007"
id="path2271" />
</g>
</g>
<text
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="342.21133"
y="384.8981"
id="text2275"><tspan
id="tspan2279"
sodipodi:role="line"
y="384.89810"
x="342.21133">header</tspan></text>
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2283"
width="223.48137"
height="99.596283"
x="46.366730"
y="650.83508" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="53.664009"
y="693.75391"
id="text2285"
sodipodi:linespacing="120.00000%"><tspan
id="tspan2337"
sodipodi:role="line"
y="693.75391"
x="53.664009">extract(out : outputStream) : void</tspan><tspan
id="tspan2339"
sodipodi:role="line"
y="708.15391"
x="53.664009">getLength() : int</tspan><tspan
id="tspan2341"
sodipodi:role="line"
y="722.55391"
x="53.664009">getEncoding() : encoding</tspan><tspan
id="tspan2343"
sodipodi:role="line"
y="736.95391"
x="53.664009">isEmpty() : bool</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="107.50659"
y="666.90515"
id="text2289"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2295"
sodipodi:role="line"
y="666.90515"
x="107.50659">contentHandler</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 46.694654,675.24013 L 269.50523,675.24013"
id="path2293" />
<text
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="96.439804"
y="606.38623"
id="text2313"><tspan
id="tspan2331"
sodipodi:role="line"
y="606.38623"
x="96.439804">contents</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2343873;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 16.600928,494.52517 L 54.665082,494.52517"
id="path2357" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="114.21628"
y="211.67206"
id="text2359"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2361"
sodipodi:role="line"
y="211.67206"
x="114.21628">0..n</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="15.201084"
y="211.39832"
id="text2363"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2371"
sodipodi:role="line"
y="211.39832"
x="15.201084">sub-parts</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="37.547035"
y="486.67206"
id="text2367"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2369"
sodipodi:role="line"
y="486.67206"
x="37.547035">0</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500843;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2355"
width="15.541844"
height="15.541844"
x="-313.66727"
y="385.82047"
transform="matrix(0.707107,-0.707107,0.707107,0.707107,0.000000,0.000000)" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2383"
width="171.85686"
height="67.987976"
x="169.86403"
y="15.308525" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="228.35699"
y="31.574478"
id="text2393"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2399"
sodipodi:role="line"
y="31.574478"
x="228.35699">message</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 170.22863,39.909422 L 341.34134,39.909422"
id="path2397" />
<path
id="path2405"
d="M 266.45394,117.77798 L 238.56502,117.77798 L 252.97430,132.18725 L 266.45394,117.77798 z "
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
</g>
<path
id="path5436"
d="M 446.81292,350.17443 L 782.69938,350.17443"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2515085;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path2373"
d="M 16.806908,219.05029 L 16.806908,493.94805"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2522694;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,621 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="629.28000pt"
height="615.89000pt"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.42.2"
sodipodi:docbase="/home/vincent/projects/vmime/doc/book/images"
sodipodi:docname="messaging-services.svg"
inkscape:export-filename="/home/vincent/www/vmime/documentation/images/design-messaging.png"
inkscape:export-xdpi="74.639999"
inkscape:export-ydpi="74.639999">
<defs
id="defs3">
<marker
inkscape:stockid="Torso"
orient="auto"
refY="0.0"
refX="0.0"
id="Torso"
style="overflow:visible">
<g
id="g2045"
transform="scale(0.7)">
<path
sodipodi:nodetypes="ccccc"
id="path1128"
d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none" />
<path
sodipodi:nodetypes="cc"
id="path1909"
d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none" />
<path
sodipodi:nodetypes="cc"
id="path1910"
d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none" />
<rect
transform="matrix(0.527536,-0.849533,0.887668,0.460484,0.000000,0.000000)"
y="-1.7408575"
x="-10.391706"
height="2.7608147"
width="2.6366582"
id="rect2035"
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
<rect
transform="matrix(0.671205,-0.741272,0.790802,0.612072,0.000000,0.000000)"
y="-7.9629307"
x="4.9587269"
height="2.8614161"
width="2.7327356"
id="rect2036"
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
<path
transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,25.96648,19.71619)"
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
sodipodi:ry="0.60731727"
sodipodi:rx="0.60731727"
sodipodi:cy="-28.685045"
sodipodi:cx="16.172634"
id="path2037"
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
sodipodi:type="arc" />
<path
transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,26.82450,16.99126)"
d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
sodipodi:ry="0.60731727"
sodipodi:rx="0.60731727"
sodipodi:cy="-28.685045"
sodipodi:cx="16.172634"
id="path2038"
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
sodipodi:type="arc" />
</g>
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0.0"
refX="0.0"
id="TriangleOutL"
style="overflow:visible">
<path
sodipodi:nodetypes="cccc"
id="path5324"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
transform="scale(0.8)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.75785828"
inkscape:cx="365.32198"
inkscape:cy="407.27112"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="1150"
inkscape:window-height="986"
inkscape:window-x="0"
inkscape:window-y="30" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<path
id="path5442"
d="M 495.30781,321.26414 L 495.30781,390.57215"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5440"
d="M 662.55216,389.28102 L 662.55216,456.99397"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<path
id="path5438"
d="M 325.22881,389.28102 L 325.22881,456.99397"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
transform="matrix(0.866025,0.499999,-0.499999,0.866025,111.0615,336.6054)"
id="g3452">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
d="M 278.87323,198.08204 L 405.25462,198.08204"
id="path3454" />
<g
transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
id="g3456">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 278.87321,217.60074 L 289.31646,228.04398"
id="path3458" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 279.22547,217.92243 L 289.41027,207.73763"
id="path3460" />
</g>
</g>
<g
transform="matrix(-0.499998,0.866024,-0.866024,-0.499998,528.2205,319.3107)"
id="g3396">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
d="M 278.87323,198.08204 L 405.25462,198.08204"
id="path3398" />
<g
transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
id="g3400">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 278.87321,217.60074 L 289.31646,228.04398"
id="path3402" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 279.22547,217.92243 L 289.41027,207.73763"
id="path3404" />
</g>
</g>
<g
transform="matrix(0.500000,0.866024,-0.866024,0.500000,431.6077,-252.3913)"
id="g3200">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
d="M 278.87323,198.08204 L 405.25462,198.08204"
id="path3202" />
<g
transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
id="g3204">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 278.87321,217.60074 L 289.31646,228.04398"
id="path3206" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 279.22547,217.92243 L 289.41027,207.73763"
id="path3208" />
</g>
</g>
<g
transform="matrix(0.499999,-0.866025,0.866025,0.499999,-54.36140,359.0658)"
id="g3168">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
d="M 278.87323,198.08204 L 405.25462,198.08204"
id="path3156" />
<g
transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
id="g3158">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 278.87321,217.60074 L 289.31646,228.04398"
id="path3160" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 279.22547,217.92243 L 289.41027,207.73763"
id="path3162" />
</g>
</g>
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect1291"
width="144.63049"
height="123.75754"
x="423.21133"
y="200.65219" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="430.8407"
y="243.43631"
id="text1293"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3116"
sodipodi:role="line"
y="243.43631"
x="430.84070">connect() : void</tspan><tspan
id="tspan3118"
sodipodi:role="line"
y="257.83631"
x="430.84070">disconnect() : void</tspan><tspan
id="tspan3120"
sodipodi:role="line"
y="272.23631"
x="430.84070">isConnected() : bool</tspan><tspan
id="tspan3122"
sodipodi:role="line"
y="286.63631"
x="430.84070">noop() : void</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="473.4863"
y="216.58759"
id="text2347"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2932"
sodipodi:role="line"
y="216.58759"
x="473.48630">service</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 423.62452,224.92254 L 567.67587,224.92254"
id="path2351" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2353"
width="254.50919"
height="106.53888"
x="40.771675"
y="200.75146" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="49.807129"
y="243.64157"
id="text2355"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3148"
sodipodi:role="line"
y="243.64157"
x="49.807129">getTransport(url : url) : ref &lt;transport&gt;</tspan><tspan
id="tspan3150"
sodipodi:role="line"
y="258.04157"
x="49.807129">getStore(url : url) : ref &lt;store&gt;</tspan><tspan
id="tspan3152"
sodipodi:role="line"
y="272.44157"
x="49.807129">getProperties() : propertySet</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="143.33478"
y="216.79285"
id="text2375"
sodipodi:linespacing="100.00000%"><tspan
id="tspan3124"
sodipodi:role="line"
y="216.79285"
x="143.33478">session</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 41.137120,225.12780 L 294.90028,225.12780"
id="path2379" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2433"
width="219.00885"
height="100.80741"
x="215.20381"
y="429.00940" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="223.58997"
y="472.3562"
id="text2435"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3110"
sodipodi:role="line"
y="472.35620"
x="223.58997">getDefaultFolder() : ref &lt;folder&gt;</tspan><tspan
id="tspan3112"
sodipodi:role="line"
y="486.75620"
x="223.58997">getRootFolder() : ref &lt;folder&gt;</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="309.11777"
y="445.50742"
id="text2439"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2936"
sodipodi:role="line"
y="445.50742"
x="309.11777">store</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 216.61640,453.84241 L 433.36337,453.84241"
id="path2443" />
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect2447"
width="219.00674"
height="101.04262"
x="553.75336"
y="428.77499" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="561.0639"
y="472.20447"
id="text2449"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3114"
sodipodi:role="line"
y="472.20447"
x="561.06390">send(msg : ref &lt;message&gt;) : void</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="632.07196"
y="445.35568"
id="text2453"
sodipodi:linespacing="100.00000%"><tspan
id="tspan2934"
sodipodi:role="line"
y="445.35568"
x="632.07196">transport</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 554.08593,453.69062 L 771.88660,453.69062"
id="path2457" />
<path
id="path2575"
d="M 481.88130,340.17064 L 509.77022,340.17064 L 495.36094,325.76137 L 481.88130,340.17064 z "
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<g
transform="translate(17.15883,45.55696)"
id="g3136">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 405.51967,217.85706 L 279.13828,217.85706"
id="path2265" />
<g
style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
id="g3132">
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 278.87321,217.60074 L 289.31646,228.04398"
id="path2269" />
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
d="M 279.22547,217.92243 L 289.41027,207.73763"
id="path2271" />
</g>
</g>
<text
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="335.37018"
y="257.45505"
id="text2275"><tspan
id="tspan3146"
sodipodi:role="line"
y="257.45505"
x="335.37018">session</tspan></text>
<text
transform="matrix(0.500000,0.866025,-0.866025,0.500000,0.000000,0.000000)"
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:11.999973px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="313.42676"
y="-318.0412"
id="text3174"><tspan
id="tspan3178"
sodipodi:role="line"
y="-318.04120"
x="313.42676">&lt;instanciates&gt;</tspan></text>
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect3180"
width="253.81813"
height="96.037521"
x="234.02649"
y="9.0948601" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="241.24963"
y="52.019093"
id="text3182"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3218"
sodipodi:role="line"
y="52.019093"
x="241.24963">create(protocol : string) : ref &lt;service&gt;</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="312.24161"
y="25.170307"
id="text3192"
sodipodi:linespacing="100.00000%"><tspan
id="tspan3198"
sodipodi:role="line"
y="25.170307"
x="312.24161">serviceFactory</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 234.44127,33.505080 L 487.67742,33.505080"
id="path3196" />
<text
transform="matrix(0.500000,-0.866025,0.866025,0.500000,0.000000,0.000000)"
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:11.999965px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="-19.006903"
y="316.46106"
id="text3210"><tspan
id="tspan3214"
sodipodi:role="line"
y="316.46106"
x="-19.006903">&lt;uses&gt;</tspan></text>
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect3362"
width="244.86130"
height="116.61144"
x="14.277589"
y="572.10736" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="22.589966"
y="615.3562"
id="text3364"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3386"
sodipodi:role="line"
y="615.35620"
x="22.589966">getName() : string</tspan><tspan
id="tspan3388"
sodipodi:role="line"
y="629.75620"
x="22.589966">open() : void</tspan><tspan
id="tspan3390"
sodipodi:role="line"
y="644.15620"
x="22.589966">close() : void</tspan><tspan
id="tspan3392"
sodipodi:role="line"
y="658.55620"
x="22.589966">getMessages(int from, int to) : vector</tspan><tspan
id="tspan3394"
sodipodi:role="line"
y="672.95620"
x="22.589966">...</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="119.45631"
y="588.50739"
id="text3370"
sodipodi:linespacing="100.00000%"><tspan
id="tspan3376"
sodipodi:role="line"
y="588.50739"
x="119.45631">folder</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2449049;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 15.691587,596.84241 L 258.28817,596.84241"
id="path3374" />
<text
transform="matrix(0.500000,-0.866025,0.866025,0.500000,0.000000,0.000000)"
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:11.999992px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="-398.12543"
y="406.40524"
id="text3406"><tspan
id="tspan3408"
sodipodi:role="line"
y="406.40524"
x="-398.12543">&lt;instanciates&gt;</tspan></text>
<rect
style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
id="rect3410"
width="244.86130"
height="140.35690"
x="365.27762"
y="617.23462" />
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="373.59"
y="660.3562"
id="text3412"
sodipodi:linespacing="120.00000%"><tspan
id="tspan3440"
sodipodi:role="line"
y="660.35620"
x="373.59000">getNumber() : int</tspan><tspan
id="tspan3442"
sodipodi:role="line"
y="674.75620"
x="373.59000">getFlags() : int</tspan><tspan
id="tspan3444"
sodipodi:role="line"
y="689.15620"
x="373.59000">getHeader() : int</tspan><tspan
id="tspan3446"
sodipodi:role="line"
y="703.55620"
x="373.59000">getStructure() : structure</tspan><tspan
id="tspan3448"
sodipodi:role="line"
y="717.95620"
x="373.59000">extract(out : outputStream) : void</tspan><tspan
id="tspan3450"
sodipodi:role="line"
y="732.35620"
x="373.59000">...</tspan></text>
<text
xml:space="preserve"
style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="459.11771"
y="633.50739"
id="text3424"
sodipodi:linespacing="100.00000%"><tspan
id="tspan3430"
sodipodi:role="line"
y="633.50739"
x="459.11771">message</tspan></text>
<path
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2449049;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
d="M 366.69159,641.84241 L 609.28817,641.84241"
id="path3428" />
<text
transform="matrix(0.866025,0.500000,-0.500000,0.866025,0.000000,0.000000)"
sodipodi:linespacing="100.00000%"
xml:space="preserve"
style="font-size:11.999992px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
x="558.315"
y="419.37476"
id="text3462"><tspan
id="tspan3464"
sodipodi:role="line"
y="419.37476"
x="558.31500">&lt;instanciates&gt;</tspan></text>
</g>
<path
id="path5436"
d="M 325.97175,390.06210 L 661.85821,390.06210"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2515085;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
<rect
y="102.22088"
x="-7.6927943"
height="76.000000"
width="106.00000"
id="rect3358"
style="fill:none;fill-opacity:1.0000000;fill-rule:nonzero;stroke:none;stroke-width:1.2500000;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000" />
<rect
y="170.36218"
x="668.00000"
height="76.000000"
width="134.00000"
id="rect3360"
style="stroke-opacity:1.0000000;stroke-dashoffset:0.0000000;stroke-miterlimit:4.0000000;stroke-linejoin:miter;stroke-linecap:round;stroke-width:1.2500000;stroke:none;fill-rule:nonzero;fill-opacity:1.0000000;fill:none" />
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

90
doc/book/intro.tex Normal file
View File

@ -0,0 +1,90 @@
\chapter{Introduction}
% ============================================================================
\section{Overview}
VMime is a powerful C++ class library for working with MIME messages and
Internet messaging services like IMAP, POP or SMTP.
With VMime you can parse, generate and modify messages, and also connect to
store and transport services to receive or send messages over the Internet.
The library offers all the features to build a complete mail client.
The main objectives of this library are:
\begin{itemize}
\item fully RFC-compliant implementation;
\item object-oriented and modular design;
\item very easy-to-use (intuitive design);
\item well documented code;
\item very high reliability;
\item maximum portability.
\end{itemize}
% ============================================================================
\section{Features}
\noindent MIME features:
\begin{itemize}
\item Full support for RFC-2822 and multipart messages (RFC-1521)
\item Aggregate documents (MHTML) and embedded objects (RFC-2557)
\item Message Disposition Notification (RFC-3798)
\item 8-bit MIME (RFC-2047)
\item Encoded word extensions (RFC-2231)
\item Attachments
\end{itemize}
\noindent Network features:
\begin{itemize}
\item Support for IMAP, POP3 and maildir stores
\item Support for SMTP and sendmail transport methods
\item Extraction of whole message or specific parts
\item TLS/SSL security layer
\item SASL authentication
\end{itemize}
% ============================================================================
\section{Copyright and license}
VMime library is Free Software and is licensed under the terms of the GNU
General Public License\footnote{See Appendix \ref{appendix_license} and
\url{http://www.gnu.org/copyleft/gpl.html}} (GPL):
\begin{verbatim}
Copyright (C) 2002-2005 Vincent Richard
VMime library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
VMime is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Linking this library statically or dynamically with other
modules is making a combined work based on this library.
Thus, the terms and conditions of the GNU General Public
License cover the whole combination.
\end{verbatim}
\newpage
\noindent This document is released under the terms of the
GNU Free Documentation
License\footnote{See \url{http://www.gnu.org/copyleft/fdl.html}} (FDL):
\begin{verbatim}
Copyright (C) 2004-2005 Vincent Richard
Permission is granted to copy, distribute and/or modify
this document under the terms of the GNU Free Documentation
License, Version 1.2 or any later version published by the
Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and no Back-Cover Texts.
\end{verbatim}

385
doc/book/msg.tex Normal file
View File

@ -0,0 +1,385 @@
\chapter{Parsing and Building Messages}
% ============================================================================
\section{Parsing messages}
\subsection{Introduction} % --------------------------------------------------
Parsing is the process of creating a structured representation (for example,
a hierarchy of C++ objects) of a message from its ``textual'' representation
(the raw data that is actually sent on the Internet).
For example, say you have the following email in a file called "hello.eml":
\begin{verbatim}
Date: Thu, Oct 13 2005 15:22:46 +0200
From: Vincent <vincent@vmime.org>
To: you@vmime.org
Subject: Hello from VMime!
A simple message to test VMime
\end{verbatim}
The following code snippet shows how you can easily obtain a
{\vcode vmime::message} object from data in this file:
\begin{lstlisting}[caption={Parsing a message from a file}]
// Read data from file
std::ifstream file;
file.open("hello.eml", std::ios::in | std::ios::binary);
vmime::utility::inputStreamAdapter is(file);
vmime::string data;
vmime::utility::outputStreamStringAdapter os(data);
vmime::utility::bufferedStreamCopy(is, os);
// Actually parse the message
vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
msg->parse(data);
vmime::ref <vmime::header> hdr = msg->getHeader();
vmime::ref <vmime::body> bdy = msg->getBody();
// Now, you can extract some of its components
vmime::charset ch(vmime::charsets::UTF_8);
std::cout
<< "The subject of the message is: "
<< hdr->Subject()->getValue().getDecodedText(ch)
<< std::endl
<< "It was sent by: "
<< hdr->From()->getValue().getName().getDecodedText(ch)
<< " (email: " << hdr->From()->getValue().getEmail() << ")"
<< std::endl;
\end{lstlisting}
The output of this program is:
\begin{verbatim}
The subject of the message is: Hello from VMime!
It was sent by: Vincent (email: vincent@vmime.org)
\end{verbatim}
\subsection{Using the {\vcode vmime::messageParser} object} % ----------------
The {\vcode vmime::messageParser} object allows to parse messages in a more
simple manner. You can obtain all the text parts and attachments as well as
basic fields (expeditor, recipients, subject...), without dealing with
MIME message structure.
\begin{lstlisting}[caption={Using {\vcode vmime::messageParser} to parse
more complex messages}]
// Read data from file
std::ifstream file;
file.open("hello.eml", std::ios::in | std::ios::binary);
vmime::utility::inputStreamAdapter is(file);
vmime::string data;
vmime::utility::outputStreamStringAdapter os(data);
vmime::utility::bufferedStreamCopy(is, os);
// Actually parse the message
vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
msg->parse(data);
// Here start the differences with the previous example
vmime::messageParser mp(msg);
// Output information about attachments
std::cout << "Message has " << mp.getAttachmentCount()
<< " attachment(s)" << std::endl;
for (int i = 0 ; i < mp.getAttachmentCount() ; ++i)
{
vmime::ref <const vmime::attachment> att = mp.getAttachmentAt(i);
std::cout << " - " << att->getType().generate() << std::endl;
}
// Output information about text parts
std::cout << "Message has " << mp.getTextPartCount()
<< " text part(s)" << std::endl;
for (int i = 0 ; i < mp.getTextPartCount() ; ++i)
{
vmime::ref <const vmime::textPart> tp = mp.getTextPartAt(i);
// text/html
if (tp->getType().getSubType() == vmime::mediaTypes::TEXT_HTML)
{
vmime::ref <const vmime::htmlTextPart> htp =
tp.dynamicCast <const vmime::htmlTextPart>();
// HTML text is in tp->getText()
// Plain text is in tp->getPlainText()
// Enumerate embedded objects
for (int j = 0 ; j < htp->getObjectCount() ; ++j)
{
vmime::ref <const vmime::htmlTextPart::embeddedObject> obj =
htp->getObjectAt(j);
// Identifier (Content-Id or Content-Location) is obj->getId()
// Object data is in obj->getData()
}
}
// text/plain or anything else
else
{
// Text is in tp->getText()
}
}
\end{lstlisting}
% ============================================================================
\section{Building messages}
\subsection{A simple message\label{msg-building-simple-message}} % -----------
Of course, you can build a MIME message from scratch by creating the various
objects that compose it (parts, fields, etc.). The following is an example of
how to achieve it:
\begin{lstlisting}[caption={Building a simple message from scratch}]
vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
vmime::ref <vmime::header> hdr = msg->getHeader();
vmime::ref <vmime::body> bdy = msg->getBody();
vmime::headerFieldFactory* hfFactory =
vmime::headerFieldFactory::getInstance();
// Append a 'Date:' field
vmime::ref <vmime::headerField> dateField =
hfFactory->create(vmime::fields::DATE);
dateField->setValue(vmime::datetime::now());
hdr->appendField(dateField);
// Append a 'Subject:' field
vmime::ref <vmime::headerField> subjectField =
hfFactory->create(vmime::fields::SUBJECT);
subjectField->setValue(vmime::text("Message subject"));
hdr->appendField(subjectField);
// Append a 'From:' field
vmime::ref <vmime::headerField> fromField =
hfFactory->create(vmime::fields::FROM);
fromField->setValue
(vmime::create <vmime::mailbox>("me@vmime.org"));
hdr->appendField(fromField);
// Append a 'To:' field
vmime::ref <vmime::headerField> toField =
hfFactory->create(vmime::fields::TO);
vmime::ref <vmime::mailboxList> recipients =
vmime::create <vmime::mailboxList>();
recipients->appendMailbox
(vmime::create <vmime::mailbox>("you@vmime.org"));
toField->setValue(recipients);
hdr->appendField(toField);
// Set the body contents
bdy->setContents(vmime::create <vmime::stringContentHandler>
("This is the text of your message..."));
// Output raw message data to standard output
vmime::utility::outputStreamAdapter out(std::cout);
msg->generate(out);
\end{lstlisting}
As you can see, this is a little fastidious. Hopefully, VMime also offers a
more simple way for creating messages. The {\vcode vmime::messageBuilder}
object can create basic messages that you can then customize.
The following code can be used to build exactly the same message as in the
previous example, using the {\vcode vmime::messageBuilder} object:
\begin{lstlisting}[caption={Building a simple message
using {\vcode vmime::messageBuilder}}]
try
{
vmime::messageBuilder mb;
// Fill in some header fields and message body
mb.setSubject(vmime::text("Message subject"));
mb.setExpeditor(vmime::mailbox("me@vmime.org"));
mb.getRecipients().appendAddress
(vmime::create <vmime::mailbox>("you@vmime.org"));
mb.getTextPart()->setCharset(vmime::charsets::ISO8859_15);
mb.getTextPart()->setText(vmime::create <vmime::stringContentHandler>
("This is the text of your message..."));
// Message construction
vmime::ref <vmime::message> msg = mb.construct();
// Output raw message data to standard output
vmime::utility::outputStreamAdapter out(std::cout);
msg->generate(out);
}
// VMime exception
catch (vmime::exception& e)
{
std::cerr << "vmime::exception: " << e.what() << std::endl;
}
// Standard exception
catch (std::exception& e)
{
std::cerr << "std::exception: " << e.what() << std::endl;
}
\end{lstlisting}
\subsection{Adding an attachment} % ------------------------------------------
Dealing with attachments is quite simple. Add the following code to the
previous example to attach a file to the message:
\begin{lstlisting}[caption={Building a message with an attachment using
{\vcode vmime::messageBuilder}}]
// Create an attachment
vmime::ref <vmime::fileAttachment> att =
vmime::create <vmime::fileAttachment>
(
/* full path to file */ "/home/vincent/paris.jpg",
/* content type */ vmime::mediaType("image/jpeg),
/* description */ vmime::text("My holidays in Paris")
);
// You can also set some infos about the file
att->getFileInfo().setFilename("paris.jpg");
att->getFileInfo().setCreationDate
(vmime::datetime("30 Apr 2003 14:30:00 +0200"));
// Add this attachment to the message
mb.appendAttachment(att);
\end{lstlisting}
\subsection{HTML messages and embedded objects} % ----------------------------
VMime also supports aggregated messages, which permits to build MIME messages
containing HTML text and embedded objects (such as images).
Creating such messages is quite easy, using the {\vcode vmime::messageBuilder}
object. The following code constructs a message containing text in both plain
and HTML format, and a JPEG image:
\begin{lstlisting}[caption={Building an HTML message with an embedded image
using the {\vcode vmime::messageBuilder}}]
// Fill in some header fields
mb.setSubject(vmime::text("An HTML message"));
mb.setExpeditor(vmime::mailbox("me@vmime.org"));
mb.getRecipients().appendAddress
(vmime::create <vmime::mailbox>("you@vmime.org"));
// Set the content-type to "text/html": a text part factory must be
// available for the type you are using. The following code will make
// the message builder construct the two text parts.
mb.constructTextPart(vmime::mediaType
(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_HTML));
// Set contents of the text parts; the message is available in two formats:
// HTML and plain text. The HTML format also includes an embedded image.
vmime::ref <vmime::htmlTextPart> textPart =
mb.getTextPart().dynamicCast <vmime::htmlTextPart>();
// -- add the JPEG image (the returned identifier is used to identify the
// -- embedded object in the HTML text, the famous "CID", or "Content-Id")
vmime::string id = textPart->addObject("<...image data...>",
vmime::mediaType(vmime::mediaTypes::IMAGE, vmime::mediaTypes::IMAGE_JPEG));
// -- set the text
textPart->setCharset(vmime::charsets::ISO8859_15);
textPart->setText(vmime::create <vmime::stringContentHandler>
("This is the <b>HTML text</b>, and the image:<br/>"
"<img src=\"") + id + vmime::string("\"/>"));
textPart->setPlainText(vmime::create <vmime::stringContentHandler>
("This is the plain text."));
\end{lstlisting}
This will create a message having the following structure:
\begin{verbatim}
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
\end{verbatim}
% ============================================================================
\section{Working with attachments: the attachment helper}
The {\vcode attachmentHelper} object allows listing all attachments in a
message, as well as adding new attachments, without using the
{\vcode messageParser} and {\vcode messageBuilders} objects. It can work
directly on messages and body parts.
To use it, you do not need any knowledge about how attachment parts should
be organized in a MIME message.
The following code snippet tests if a body part is an attachment, and if so,
extract its contents to the standard output:
\begin{lstlisting}[caption={Testing if a body part is an attachment}]
vmime::ref <vmime::bodyPart> part; // suppose we have a body part
if (vmime::attachmentHelper::isBodyPartAnAttachment(part))
{
// The body part contains an attachment, get it
vmime::ref <const vmime::attachment> attach =
attachmentHelper::getBodyPartAttachment(part);
// Extract attachment data to standard output
vmime::utility::outputStreamAdapter out(std::cout);
attach->getData()->extract(out);
}
\end{lstlisting}
You can also easily extract all attachments from a message:
\begin{lstlisting}[caption={Extracting all attachments from a message}]
vmime::ref <vmime::message> msg; // suppose we have a message
const std::vector <ref <const attachment> > atts =
attachmentHelper::findAttachmentsInMessage(msg);
\end{lstlisting}
Finally, the {\vcode attachmentHelper} object can be used to add an
attachment to an existing message, whatever it contains (text parts,
attachments, ...). The algorithm can modify the structure of the
message if needed (eg. add a \emph{multipart/mixed} part if no one
exists in the message). Simply call the {\vcode addAttachment}
function:
\begin{lstlisting}[caption={Adding an attachment to an existing message}]
vmime::ref <vmime::message> msg; // suppose we have a message
// Create an attachment
vmime::ref <vmime::fileAttachment> att =
vmime::create <vmime::fileAttachment>
(
/* full path to file */ "/home/vincent/paris.jpg",
/* content type */ vmime::mediaType("image/jpeg),
/* description */ vmime::text("My holidays in Paris")
);
// Attach it to the message
vmime::attachmentHelper::addAttachment(msg, att);
\end{lstlisting}

946
doc/book/net.tex Normal file
View File

@ -0,0 +1,946 @@
\chapter{Working with Messaging Services}
% ============================================================================
\section{Introduction}
In addition to parsing and building MIME messages, VMime also offers a lot of
features to work with messaging services. This includes connecting to remote
messaging stores (like IMAP or POP3), local stores (maildir) and transport
services (send messages over SMTP or local sendmail), through an unified
interface (see Figure \ref{uml_messaging_module}). That means that you can
use independently IMAP of POP3 without having to change any line of code.
Source code of {\vexample Example6} covers all features presented in this
chapter, so it is important you take some time to read it.
\begin{figure}
\center\includegraphics[width=0.9\textwidth]
{images/messaging-services.png}
\caption{Overall structure of the messaging module}
\label{uml_messaging_module}
\end{figure}
The interface is composed of five classes:
\begin{itemize}
\item {\vcode vmime::net::service}: this is the base interface for a
messaging service. It can be either a store service or a transport
service.
\item {\vcode vmime::net::serviceFactory}: create instances of a service.
This is used internally by the session object (see below).
\item {\vcode vmime::net::store}: interface for a store service. A store
service offers access to a set of folders containing messages. This is
used for IMAP, POP3 and maildir.
\item {\vcode vmime::net::transport}: interface for a transport service.
A transport service is capable of sending messages. This is used for
SMTP and sendmail.
\item {\vcode vmime::net::session}: a session oject is used to store the
parameters used by a service (eg. connection parameters). Each service
instance is associated with only one session. The session object is capable
of creating instances of services.
\end{itemize}
The following classes are specific to store services:
\begin{itemize}
\item {\vcode vmime::net::folder}: a folder can either contain other folders
or messages, or both.
\item {\vcode vmime::net::message}: this is the interface for dealing with
messages. For a given message, you can have access to its flags, its MIME
structure and you can also extract the whole message data or given parts (if
supported by the underlying protocol).
\end{itemize}
% ============================================================================
\section{Working with sessions}
\subsection{Setting properties} % --------------------------------------------
Sessions are used to store configuration parameters for services. They
contains a set of typed properties that can modify the behaviour of the
services. Before using a messaging service, you must create and
initialize a session object:
\begin{lstlisting}
vmime::ref <net::session> theSession = vmime::create <net::session>();
\end{lstlisting}
Session properties include:
\begin{itemize}
\item connection parameters: host and port to connect to;
\item authentication parameters: user credentials required to use the
service (if any);
\item protocol-specific parameters: enable or disable extensions (eg. APOP
support in POP3).
\end{itemize}
Properties are stored using a dotted notation, to specify the service type,
the protocol name, the category and the name of the property:
\begin{verbatim}
{service_type}.{protocol}.category.name
\end{verbatim}
An example of property is \emph{store.pop3.options.apop} (used to enable or
disable the use of APOP authentication). The \emph{store.pop3} part is called
the \emph{prefix}. This allow specifying different values for the same
property depending on the protocol used.
The session properties are stored in a {\vcode vmime::propertySet} object.
To set the value of a property, you can use either:
\begin{lstlisting}
theSession->getProperties().setProperty("property-name", value);
\end{lstlisting}
or:
\begin{lstlisting}
theSession->getProperties()["property-name"] = value;
\end{lstlisting}
\subsection{Available properties} % ------------------------------------------
Following is a list of available properties and the protocols they apply to,
as the time of writing this documentation\footnote{You can get an up-to-date
list of the properties by running \vexample{Example7}}. For better clarity,
the prefixes do not appear in this table.
\begin{table}[!ht]
\noindent\begin{tabularx}{1.0\textwidth}{|l|c|X|c|c|c|c|c|c|c|c|}
\hline
{\bf Property name} &
{\bf Type} &
{\bf Description} &
\verti{\bf POP3} &
\verti{\bf POP3S} &
\verti{\bf IMAP} &
\verti{\bf IMAPS} &
\verti{\bf SMTP} &
\verti{\bf SMTPS} &
\verti{\bf maildir} &
\verti{\bf sendmail} \\
\hline
\hline
options.sasl & bool & Set to {\vcode true} to use SASL authentication, if
available. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
\hline
options.sasl.fallback & bool & Fail if SASL authentication failed (do not
try other authentication mechanisms). & \vdot & \vdot & \vdot & \vdot &
\vdot & \vdot & & \\
\hline
auth.username\footnote{You should use authenticators
instead.\label{fn_auth_username}} & string & Set the username of the account
to connect to. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
\hline
auth.password\footref{fn_auth_username} & string & Set the password of the
account. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
\hline
connection.tls & bool & Set to {\vcode true} to start a secured connection
using STARTTLS extension, if available. & \vdot & & \vdot & & \vdot & & & \\
\hline
connection.tls.required & bool & Fail if a secured connection cannot be
started. & \vdot & & \vdot & & \vdot & & & \\
\hline
server.address & string & Server host name or IP address. &\vdot & \vdot &
\vdot & \vdot & \vdot & \vdot & & \\
\hline
server.port & int & Server port. & \vdot & \vdot & \vdot & \vdot &
\vdot & \vdot & & \\
\hline
server.rootpath & string & Root directory for mail repository (eg.
\emph{/home/vincent/Mail}). & & & & & & & \vdot & \\
\hline
\end{tabularx}
\caption{Properties common to all protocols}
\end{table}
\newpage
These are the protocol-specific options:
\begin{table}[!ht]
\noindent\begin{tabularx}{1.0\textwidth}{|l|c|X|}
\hline
{\bf Property name} &
{\bf Type} &
{\bf Description} \\
% POP3/POP3S
\hline
\multicolumn{3}{|c|}{POP3, POP3S} \\
\hline
store.pop3.options.apop & bool & Enable or disable authentication with
APOP (if SASL is enabled, this occurs after all SASL mechanisms have been
tried). \\
\hline
store.pop3.options.apop.fallback & bool & If set to {\vcode true} and
APOP fails, the authentication process fails (ie. unsecure plain text
authentication is not used). \\
\hline
% SMTP
\multicolumn{3}{|c|}{SMTP, SMTPS} \\
\hline
transport.smtp.options.need-authentication & bool & Set to \emph{true} if
the server requires to authenticate before sending messages. \\
\hline
% sendmail
\multicolumn{3}{|c|}{sendmail} \\
\hline
transport.sendmail.binpath & string & The path to the \emph{sendmail}
executable on your system. The default is the one found by the configuration
script when VMime was built. \\
\hline
\end{tabularx}
\caption{Protocol-specific options}
\end{table}
\subsection{Instanciating services} % ----------------------------------------
You can create a service either by specifying its protocol name, or by
specifying the URL of the service. Creation by name is deprecated so
this chapter only presents the latter option.
The URL scheme for connecting to services is:
\begin{verbatim}
protocol://[username[:password]@]host[:port]/[root-path]
\end{verbatim}
\vnote{For local services (ie. \emph{sendmail} and \emph{maildir}), the host
part is not used, but it must not be empty (you can use "localhost").}
The following table shows an example URL for each service:
\noindent\begin{tabularx}{1.0\textwidth}{|c|X|}
\hline
{\bf Service} &
{\bf Connection URL} \\
\hline
imap, imaps & {\tt imap://imap.example.com},
{\tt imaps://vincent:pass@example.com} \\
\hline
pop3, pop3s & {\tt pop3://pop3.example.com} \\
\hline
smtp, smtps & {\tt smtp://smtp.example.com} \\
\hline
maildir & {\tt maildir://localhost/home/vincent/Mail} (host not used) \\
\hline
sendmail & {\tt sendmail://localhost} (host not used, always localhost) \\
\hline
\end{tabularx}
\newpage
When you have the connection URL, instanciating the service is quite simple.
Depending on the type of service, you will use either {\vcode getStore()} or
{\vcode getTransport()}. For example, for store services, use:
\begin{lstlisting}
vmime::utility:url url("imap://user:pass@imap.example.com");
vmime::ref <vmime::net::store> st = sess->getStore(url);
\end{lstlisting}
and for transport services:
\begin{lstlisting}
vmime::utility:url url("smtp://smtp.example.com");
vmime::ref <vmime::net::transport> tr = sess->getTransport(url);
\end{lstlisting}
% ============================================================================
\section{User credentials and authenticators}
Some services need some user credentials (eg. username and password) to open
a session. In VMime, user credentials can be specified in the session
properties or by using a custom authenticator (callback).
\begin{lstlisting}[caption={Setting user credentials using session
properties}]
vmime::ref <vmime::net::session> sess; // Suppose we have a session
sess->getProperties()["store.imap.auth.username"] = "vincent";
sess->getProperties()["store.imap.auth.password"] = "my-password";
\end{lstlisting}
Although not recommended, you can also specify username and password
directly in the connection URL,
ie: \emph{imap://username:password@imap.example.com/}. This works only for
services requiring an username and a password as user credentials, and no
other information.
Sometimes, it may not be very convenient to set username/password in the
session properties, or not possible (eg. extended SASL mechanisms) . That's
why VMime offers an alternate way of getting user credentials: the
{\vcode authenticator} object. Basically, an authenticator is an object that
can return user credentials on-demand (like a callback).
Currently, there are two types of authenticator in VMime: a basic
authenticator (class {\vcode vmime::security::authenticator}) and, if SASL
support is enabled, a SASL authenticator
(class {\vcode vmime::security::sasl::SASLAuthenticator}). Usually, you
should use the default implementations, or at least make your own
implementation inherit from them.
The following example shows how to use a custom authenticator to request
the user to enter her/his credentials:
\begin{lstlisting}[caption={A simple interactive authenticator}]
class myAuthenticator : public vmime::security::defaultAuthenticator
{
const string getUsername() const
{
std::cout << "Enter your username: " << std::endl;
vmime::string res;
std::getline(std::cin, res);
return res;
}
const string getPassword() const
{
std::cout << "Enter your password: " << std::endl;
vmime::string res;
std::getline(std::cin, res);
return res;
}
};
\end{lstlisting}
This is how to use it:
\begin{lstlisting}
// First, create a session
vmime::ref <vmime::net::session> sess =
vmime::create <vmime::net::session>();
// Next, initialize a service which will use our authenticator
vmime::ref <vmime::net::store> st =
sess->getStore(vmime::utility::url("imap://imap.example.com"),
/* use our authenticator */ vmime::create <myAuthenticator>());
\end{lstlisting}
\vnote{An authenticator object should be used with one and only one service
at a time. This is required because the authentication process may need to
retrieve the service name (SASL).}
Of course, this example is quite simplified. For example, if several
authentication mechanisms are tried, the user may be requested to enter the
same information multiple times. See {\vexample Example6} for a more complex
implementation of an authenticator, with caching support.
If you want to use SASL (ie. if \emph{options.sasl} is set to \emph{true}),
your authenticator must inherit from
{\vcode vmime::security::sasl::SASLAuthenticator} or
{\vcode vmime::security::sasl::defaultSASLAuthenticator}, even if you do not
use the SASL-specific methods {\vcode getAcceptableMechanisms()} and
{\vcode setSASLMechanism()}. Have a look at {\vexample Example6} to see an
implementation of an SASL authenticator.
\begin{lstlisting}[caption={A simple SASL authenticator}]
class mySASLAuthenticator : public vmime::security::sasl::defaultSASLAuthenticator
{
typedef vmime::security::sasl::SASLMechanism mechanism; // save us typing
const std::vector <vmime::ref <mechanism > getAcceptableMechanisms
(const std::vector <vmime::ref <mechanism> >& available,
vmime::ref <mechanism> suggested) const
{
// Here, you can sort the SASL mechanisms in the order they will be
// tried. If no SASL mechanism is acceptable (ie. for example, not
// enough secure), you can return an empty list.
//
// If you do not want to bother with this, you can simply return
// the default list, which is ordered by security strength.
return defaultSASLAuthenticator::
getAcceptableMechanisms(available, suggested);
}
void setSASLMechanism(vmime::ref <mechanism> mech)
{
// This is called when the authentication process is going to
// try the specified mechanism.
//
// The mechanism name is in mech->getName()
defaultSASLAuthenticator::setSASLMechanism(mech);
}
// ...implement getUsername() and getPassword()...
};
\end{lstlisting}
% ============================================================================
\section{Using transport service}
You have two possibilities for giving message data to the service when you
want to send a message:
\begin{itemize}
\item either you have a reference to a message (type {\vcode vmime::message})
and you can simply call {\vcode send(msg)};
\item or you only have raw message data (as a string, for example), and you
have to call the second overload of {\vcode send()}, which takes additional
parameters (corresponding to message envelope);
\end{itemize}
The following example illustrates the use of a transport service to send a
message using the second method:
\begin{lstlisting}[caption={Using a transport service}]
const vmime::string msgData =
"From: me@example.org \r\n"
"To: you@example.org \r\n"
"Date: Sun, Oct 30 2005 17:06:42 +0200 \r\n"
"Subject: Test \r\n"
"\r\n"
"Message body";
// Create a new session
vmime::utility::url url("smtp://example.com");
vmime::ref <vmime::net::session> sess =
vmime::create <vmime::net::session>();
// Create an instance of the transport service
vmime::ref <vmime::net::transport> tr = sess->getTransport(url);
// Connect it
tr->connect();
// Send the message
vmime::utility::inputStreamStringAdapter is(msgData);
vmime::mailbox from("me@example.org");
vmime::mailboxList to;
to.appendMailbox(vmime::create <vmime::mailbox>("you@example.org"));
tr->send(
/* expeditor */ from,
/* recipient(s) */ to,
/* data */ is,
/* total length */ msgData.length());
// We have finished using the service
tr->disconnect();
\end{lstlisting}
\vnote{Exceptions can be thrown at any time when using a service. For better
clarity, exceptions are not caught here, but be sure to catch them in your own
application to provide error feedback to the user.}
If you use SMTP, you can enable authentication by setting some properties
on the session object ({\vcode service::setProperty()} is a shortcut for
setting properties on the session with the correct prefix):
\begin{lstlisting}
tr->setProperty("options.need-authentication", true);
tr->setProperty("auth.username", "user");
tr->setProperty("auth.password", "password");
\end{lstlisting}
% ============================================================================
\section{Using store service}
\subsection{Connecting to a store} % -----------------------------------------
The first basic step for using a store service is to connect to it. The
following example shows how to initialize a session and instanciate the
store service:
\begin{lstlisting}[caption={Connecting to a store service}]
// Create a new session
vmime::utility::url url("imap://vincent:password@imap:example.org");
vmime::ref <vmime::net::session> sess =
vmime::create <vmime::net::session>();
// Create an instance of the transport service
vmime::ref <vmime::net::store> store = sess->getStore(url);
// Connect it
store->connect();
\end{lstlisting}
\vnote{{\vexample Example6} contains a more complete example for connecting
to a store service, with support for a custom authenticator.}
\subsection{Opening a folder} % ----------------------------------------------
You can open a folder using two different access modes: either in
\emph{read-only} mode (where you can only read message flags and contents), or
in \emph{read-write} mode (where you can read messages, but also delete them
or add new ones). When you have a reference to a folder, simply call the
{\vcode open()} method with the desired access mode:
\begin{lstlisting}
folder->open(vmime::net::folder::MODE_READ_WRITE);
\end{lstlisting}
\vnote{Not all stores support the \emph{read-write} mode. By default, if the
\emph{read-write} mode is not available, the folder silently fall backs on
the \emph{read-only} mode, unless the \emph{failIfModeIsNotAvailable} argument
to {\vcode open()} is set to true.}
Call {\vcode getDefaultFolder()} on the store to obtain a reference to the
default folder, which is usually the INBOX folder (where messages arrive when
they are received).
You can also open a specific folder by specifying its path. The following
example will open a folder named \emph{bar}, which is a child of \emph{foo}
in the root folder:
\begin{lstlisting}[caption={Opening a folder from its path}]
vmime::net::folder::path path;
path /= vmime::net::folder::path::component("foo");
path /= vmime::net::folder::path::component("bar");
vmime::ref <vmime::net::folder> fld = store->getFolder(path);
fld->open(vmime::net::folder::MODE_READ_WRITE);
\end{lstlisting}
\vnote{You can specify a path as a string as there is no way to get the
separator used to delimitate path components. Always use {\vcode operator/=}
or {\vcode appendComponent}.}
\vnote{Path components are of type {\vcode vmime::word}, which means that
VMime supports folder names with extended characters, not only 7-bit
US-ASCII. However, be careful that this may not be supported by the
underlying store protocol (IMAP supports it, because it uses internally a
modified UTF-7 encoding).}
\subsection{Fetching messages} % ---------------------------------------------
You can fetch some information about a message without having to download the
whole message. Moreover, folders support fetching for multiple messages in
a single request, for better performance. The following items are currently
available for fetching:
\begin{itemize}
\item {\bf envelope}: sender, recipients, date and subject;
\item {\bf structure}: MIME structure of the message;
\item {\bf content-info}: content-type of the root part;
\item {\bf flags}: message flags;
\item {\bf size}: message size;
\item {\bf header}: retrieve all the header fields of a message;
\item {\bf uid}: unique identifier of a message;
\item {\bf importance}: fetch header fields suitable for use with
{\vcode misc::importanceHelper}.
\end{itemize}
\vnote{Not all services support all fetchable items. Call
{\vcode getFetchCapabilities()} on a folder to know which information can be
fetched by a service.}
The following code shows how to list all the messages in a folder, and
retrieve basic information to show them to the user:
\begin{lstlisting}[caption={Fetching information about multiple messages}]
std::vector <ref <vmime::net::message> > allMessages = folder->getMessages();
folder->fetchMessages(allMessages,
vmime::net::folder::FETCH_FLAGS |
vmime::net::folder::FETCH_ENVELOPE);
for (unsigned int i = 0 ; i < allMessages.size() ; ++i)
{
vmime::ref <vmime::net::message> msg = allMessages[i];
const int flags = msg->getFlags();
std::cout << "Message " << i << ":" << std::endl;
if (flags & vmime::net::message::FLAG_SEEN)
std::cout << " - is read" << std::endl;
if (flags & vmime::net::message::FLAG_DELETED)
std::cout << " - is deleted" << std::endl;
vmime::ref <const vmime::header> hdr = msg->getHeader();
std::cout << " - sent on " << hdr->Date()->generate() << std::endl;
std::cout << " - sent by " << hdr->From()->generate() << std::endl;
}
\end{lstlisting}
\subsection{Extracting messages and parts}
To extract the whole contents of a message (including headers), use the
{\vcode extract()} method on a {\vcode vmime::net::message} object. The
following example extracts the first message in the default folder:
\begin{lstlisting}[caption={Extracting messages}]
// Get a reference to the folder and to its first message
vmime::ref <vmime::net::folder> folder = store->getDefaultFolder();
vmime::ref <vmime::net::message> msg = folder->getMessage(1);
// Write the message contents to the standard output
vmime::utility::outputStreamAdapter out(std::cout);
msg->extract(out);
\end{lstlisting}
Some protocols (like IMAP) also support the extraction of specific MIME parts
of a message without downloading the whole message. This can save bandwidth
and time. The method {\vcode extractPart()} is used in this case:
\begin{lstlisting}[caption={Extracting a specific MIME part of a message}]
// Fetching structure is required before extracting a part
folder->fetchMessage(msg, vmime::net::folder::FETCH_STRUCTURE);
// Now, we can extract the part
msg->extractPart(msg->getStructure()->getPartAt(0)->getPartAt(1));
\end{lstlisting}
Suppose we have a message with the following structure:
\begin{verbatim}
multipart/mixed
text/html
image/jpeg [*]
\end{verbatim}
The previous example will extract the header and body of the \emph{image/jpeg}
part.
\subsection{Events} % --------------------------------------------------------
As a result of executing some operation (or from time to time, even if no
operation has been performed), a store service can send events to notify you
that something has changed (eg. the number of messages in a folder). These
events may allow you to update the user interface associated to a message
store.
Currently, there are three types of event:
\begin{itemize}
\item {\bf message change}: sent when the number of messages in a folder
has changed (ie. some messages have been added or removed);
\item {\bf message count change}: sent when one or more message(s) have
changed (eg. flags or deleted status);
\item {\bf folder change}: sent when a folder has been created, renamed or
deleted.
\end{itemize}
You can register a listener for each event type by using the corresponding
methods on a {\vcode folder} object: {\vcode addMessageChangedListener()},
{\vcode addMessageCountListener()} or {\vcode addFolderListener()}. For more
information, please read the class documentation for
{\vcode vmime::net::events} namespace.
% ============================================================================
\section{Handling time-outs}
Unexpected errors can occur while messaging services are performing
operations and waiting a response from the server (eg. server stops
responding, network link falls down). As all operations as synchronous,
they can be ``blocked'' a long time before returning (in fact, they loop
until they either receive a response from the server, or the underlying
socket system returns an error).
VMime provides a mechanism to control the duration of operations. This
mechanism allows the program to cancel an operation that is currently
running.
An interface called {\vcode timeoutHandler} is provided:
\begin{lstlisting}
class timeoutHandler : public object
{
/** Called to test if the time limit has been reached.
*
* @return true if the time-out delay is elapsed
*/
virtual const bool isTimeOut() = 0;
/** Called to reset the time-out counter.
*/
virtual void resetTimeOut() = 0;
/** Called when the time limit has been reached (when
* isTimeOut() returned true).
*
* @return true to continue (and reset the time-out)
* or false to cancel the current operation
*/
virtual const bool handleTimeOut() = 0;
};
\end{lstlisting}
While the operation runs, the service calls {\vcode isTimeout()} at variable
intervals. If the function returns {\vcode true}, then
{\vcode handleTimeout()} is called. If it also returns {\vcode true}, the
operation is cancelled and an {\vcode operation\_timed\_out} exception is
thrown. The function {\vcode resetTimeout()} is called each time data has
been received from the server to reset time-out delay.
The following example shows how to implement a simple time-out handler:
\begin{lstlisting}[caption={Implementing a simple time-out handler}]
class myTimeoutHandler : public vmime::net::timeoutHandler
{
public:
const bool isTimeOut()
{
return (getTime() >= m_last + 30); // 30 seconds time-out
}
void resetTimeOut()
{
m_last = getTime();
}
const bool handleTimeOut()
{
std::cout << "Operation timed out." << std::endl;
<< "Press [Y] to continue, or [N] to "
<< "cancel the operation." << std::endl;
std::string response;
std::cin >> response;
return (response == "y" || response == "Y");
}
private:
const unsigned int getTime() const
{
return vmime::platformDependant::getHandler()->getUnixTime();
}
unsigned int m_last;
};
\end{lstlisting}
% ============================================================================
\newpage
\section{Secured connection using TLS/SSL}
\subsection{Introduction} % --------------------------------------------------
If you have enabled TLS support in VMime, you can configure messaging services
so that they use a secured connection.
Quoting from RFC-2246 - the TLS 1.0 protocol specification: \emph{`` The TLS
protocol provides communications privacy over the Internet. The protocol
allows client/server applications to communicate in a way that is designed
to prevent eavesdropping, tampering, or message forgery.''}
TLS has the following advantages:
\begin{itemize}
\item authentication: server identity can be verified;
\item privacy: transmission of data between client and server cannot be read
by someone in the middle of the connection;
\item integrity: original data which is transferred between a client and a
server can not be modified by an attacker without being detected.
\end{itemize}
\vnote{What is the difference between SSL and TLS? SSL is a protocol designed
by Netscape. TLS is a standard protocol, and is partly based on version 3 of
the SSL protocol. The two protocols are not interoperable, but TLS does
support a mechanism to back down to SSL 3.}
VMime offers two possibilities for using a secured connection:
\begin{itemize}
\item you can connect to a server listening on a special port (eg. IMAPS
instead of IMAP): this is the classical use of SSL, but is now deprecated;
\item connect to a server listening on the default port, and then begin a
secured connection: this is STARTTLS.
\end{itemize}
\subsection{Setting up a secured connection} % -------------------------------
\subsubsection{Connecting to a ``secured'' port} % ...........................
To use the classical SSL/TLS way, simply use the ``S'' version of the protocol
to connect to the server (eg. \emph{imaps} instead of \emph{imap}). This is
currently available for SMTP, POP3 and IMAP.
\begin{lstlisting}
vmime::ref <vmime::net::store> store =
theSession->getStore(vmime::utility::url("imaps://example.org"));
\end{lstlisting}
\subsubsection{Using STARTTLS} % .............................................
To make the service start a secured session using the STARTTLS method, simply
set the \emph{connection.tls} property:
\begin{lstlisting}
theService->setProperty("connection.tls", true);
\end{lstlisting}
\vnote{If, for some reason, a secured connection cannot be started, the
default behaviour is to fallback on a normal connection. To make
{\vcode connect()} fail if STARTTLS fails, set the
\emph{connection.tls.required} to \emph{true}.}
\subsection{Certificate verification} % --------------------------------------
\subsubsection{How it works} % ...............................................
If you tried the previous examples, a
{\vcode certificate\_verification\_exception} might have been thrown.
This is because the default certificate verifier in VMime did not manage to
verify the certificate, and so could not trust it.
Basically, when you connect to a server using TLS, the server responds with
a list of certificates, called a certificate chain (usually, certificates are
of type X.509\footnote{And VMime currently supports only X.509 certificates}).
The certificate chain is ordered so that the first certificate is the subject
certificate, the second is the subject's issuer one, the third is the issuer's
issuer, and so on.
To decide whether the server can be trusted or not, you have to verify that
\emph{each} certificate is valid (ie. is trusted). For more information
about X.509 and certificate verification, see related articles on Wikipedia
\footnote{\url{See http://wikipedia.org/wiki/Public\_key\_certificate}}.
\subsubsection{Using the default certificate verifier} % .....................
The default certificate verifier maintains a list of root (CAs) and user
certificates that are trusted. By default, the list is empty. So, you have
to initialize it before using the verifier.
The algorithm\footnote{See
\url{http://wikipedia.org/wiki/Certification\_path\_validation\_algorithm}}
used is quite simple:
\begin{enumerate}
\item for every certificate in the chain, verify that the certificate has been
issued by the next certificate in the chain;
\item for every certificate in the chain, verify that the certificate is valid
at the current time;
\item decide whether the subject's certificate can be trusted:
\begin{itemize}
\item first, verify that the the last certificate in the chain was
issued by a third-party that we trust (root CAs);
\item if the issuer certificate cannot be verified against root CAs,
compare the subject's certificate against the trusted certificates
(the certificates the user has decided to trust).
\end{itemize}
\end{enumerate}
First, we need some code to load existing X.509 certificates:
\begin{lstlisting}[caption={Reading a X.509 certificate from a file}]
vmime::ref <vmime::security::cert::X509Certificate>
loadX509CertificateFromFile(const std::string& path)
{
std::ifstream certFile;
certFile.open(path.c_str(), std::ios::in | std::ios::binary);
if (!certFile)
{
// ...handle error...
}
vmime::utility::inputStreamAdapter is(certFile);
vmime::ref <vmime::security::cert::X509Certificate> cert;
// Try DER format
cert = vmime::security::cert::X509Certificate::import
(is, vmime::security::cert::X509Certificate::FORMAT_DER);
if (cert != NULL)
return cert;
// Try PEM format
is.reset();
cert = vmime::security::cert::X509Certificate::import
(is, vmime::security::cert::X509Certificate::FORMAT_PEM);
return cert;
}
\end{lstlisting}
Then, we can use the {\vcode loadX509CertificateFromFile} function to load
certificates and initialize the certificate verifier:
\begin{lstlisting}[caption={Using the default certificate verifier}]
vmime::ref <vmime::security::cert::defaultCertificateVerifier> vrf =
vmime::create <vmime::security::cert::defaultCertificateVerifier>();
// Load root CAs (such as Verisign or Thawte)
std::vector <vmime::ref <vmime::security::cert::X509Certificate> > rootCAs;
rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca1.cer");
rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca2.cer");
rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca3.cer");
vrf->setX509RootCAs(rootCAs);
// Then, load certificates that the user explicitely chose to trust
std::vector <vmime::ref <vmime::security::cert::X509Certificate> > trusted;
trusted.push_back(loadX509CertificateFromFile("/path/to/trusted-site1.cer");
trusted.push_back(loadX509CertificateFromFile("/path/to/trusted-site2.cer");
vrf->setX509TrustedCerts(trusted);
\end{lstlisting}
\subsubsection{Writing your own certificate verifier} % ......................
If you need to do more complex verifications on certificates, you will have to
write your own verifier. Your verifier should inherit from the
{\vcode vmime::security::cert::certificateVerifier} class and implement the
method {\vcode verify()}. Then, if the specified certificate chain is trusted,
simply return from the function, or else throw a
{\vcode certificate\_verification\_exception}.
The following example shows how to implement an interactive certificate
verifier which relies on the user's decision, and nothing else (you SHOULD NOT
use this in a production application as this is obviously a serious security
issue):
\begin{lstlisting}[caption={A custom certificate verifier}]
class myCertVerifier : public vmime::security::cert::certificateVerifier
{
public:
void verify(vmime::ref <certificateChain> certs)
{
// Obtain the subject's certificate
vmime::ref <vmime::security::cert::certificate> cert = chain->getAt(0);
std::cout << std::endl;
std::cout << "Server sent a '" << cert->getType() << "'"
<< " certificate." << std::endl;
std::cout << "Do you want to accept this certificate? (Y/n) ";
std::cout.flush();
std::string answer;
std::getline(std::cin, answer);
if (answer.length() != 0 && (answer[0] == 'Y' || answer[0] == 'y'))
return; // OK, we trust the certificate
// Don't trust this certificate
throw exceptions::certificate_verification_exception();
}
};
\end{lstlisting}
\vnote{In production code, it may be a good idea to remember user's decisions
about which certificates to trust and which not. See {\vexample Example6} for
a basic cache implementation.}

104
doc/book/start.tex Normal file
View File

@ -0,0 +1,104 @@
\chapter{Getting Started}
% ============================================================================
\section{Using VMime in your programs}
First, make sure you have successfully compiled and installed VMime using the
instructions described in Chapter \ref{chapter_building}. To use VMime in your
program, you simply have to include VMime headers:
\begin{lstlisting}
#include <vmime/vmime.hpp>
\end{lstlisting}
\vnote{for versions older than 0.6.1, include $<$vmime/vmime$>$.}
As of version 0.6.1, VMime uses {\vcode pkg-config} to simplify compiling and
linking with VMime. The {\vcode pkg-config} utility is used to detect the
appropriate compiler and linker flags needed for a library.
You can simply build your program with:
\begin{verbatim}
$ g++ `pkg-config --cflags --libs vmime` -static -o myprog myprog.cpp
\end{verbatim}
to use the static version, or with:
\begin{verbatim}
$ g++ `pkg-config --cflags --libs vmime` -o myprog myprog.cpp
\end{verbatim}
to use the shared version.
\vnote{it is highly recommended that you link your program against the shared
version of the library.}
All VMime classes and global functions are defined in the namespace
{\vcode vmime}, so prefix explicitely all your declarations which use VMime
with {\vcode vmime::}, or import the {\vcode vmime} namespace into the global
namespace with the C++ keywork {\vcode using} (not recommended, though).
% ============================================================================
\section{If you can not (or do not want to) use {\vcode pkg-config}}
{\bf Linking with the shared library (.so):} compile your program with the
{\vcode -lvmime} flag. You can use the -L path flag if the library file is
not in a standard path (ie. not in /usr/lib or /usr/local/lib).
\vnote{if you want to link your program with the shared version of VMime
library, make sure the library has been compiled using the autotools version
of the build system ({\vcode ./configure}, {\vcode make} and {\vcode make
install}). When you compile with SCons, only the static library is built and
installed.}
{\bf Linking with the static library (.a):} follow the same procedure as for
shared linking and append the flag -static to force static linking. Although
static linking is possible, you are encouraged to use the shared (dynamic)
version of the library.
% ============================================================================
\section{Platform-dependant code}
While the most part of VMime code is pure ANSI C++, there are some features
that are platform-specific: file management (opening/reading/writing files),
network code (socket, DNS resolution) and time management. All the
non-portable stuff is done by a bridge object called a platform handler (see
{\vcode vmime::platformDependant}).
If your platform is POSIX-compatible (eg. GNU/Linux, *BSD) or is Windows,
then you are lucky: VMime has built-in support for these platforms. If not,
don't worry, the sources of the built-in platform handlers are very well
documented, so writing you own should not be very difficult.
At the beginning of your program (before using \emph{any} VMime object, or
calling \emph{any} VMime global function), you should tell VMime which
platform handler you want to use.
So, if your platform is POSIX, your program should look like this:
\begin{lstlisting}[caption={Initializing VMime and the platform handler}]
#include <vmime/vmime.hpp>
#include <vmime/platforms/posix/posixHandler.hpp>
int main()
{
vmime::platformDependant::
setHandler <vmime::platforms::posix::posixHandler>();
// Now, you can use VMime
// ...do what you want, it's your program...
}
\end{lstlisting}
For using VMime on Windows, include
$<$vmime/platforms/windows/windowsHandler.hpp$>$ and use the following line
to initialize the platform handler:
\begin{lstlisting}
vmime::platformDependant::
setHandler <vmime::platforms::windows::windowsHandler>();
\end{lstlisting}