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