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

created the repository for the thymian project
author ferencd
date Tue, 17 Aug 2021 11:19:54 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:a4671277546c
1 \chapter{Working with Messaging Services}
2
3 % ============================================================================
4 \section{Introduction}
5
6 In addition to parsing and building MIME messages, VMime also offers a lot of
7 features to work with messaging services. This includes connecting to remote
8 messaging stores (like IMAP or POP3), local stores (maildir) and transport
9 services (send messages over SMTP or local sendmail), through an unified
10 interface (see Figure \ref{uml_messaging_module}). That means that you can
11 use independently IMAP of POP3 without having to change any line of code.
12
13 Source code of {\vexample Example6} covers all features presented in this
14 chapter, so it is important you take some time to read it.
15
16 \begin{figure}
17 \center\includegraphics[width=0.9\textwidth]
18 {images/messaging-services.png}\endcenter
19 \caption{Overall structure of the messaging module}
20 \label{uml_messaging_module}
21 \end{figure}
22
23 The interface is composed of five classes:
24
25 \begin{itemize}
26 \item {\vcode vmime::net::service}: this is the base interface for a
27 messaging service. It can be either a store service or a transport
28 service.
29
30 \item {\vcode vmime::net::serviceFactory}: create instances of a service.
31 This is used internally by the session object (see below).
32
33 \item {\vcode vmime::net::store}: interface for a store service. A store
34 service offers access to a set of folders containing messages. This is
35 used for IMAP, POP3 and maildir.
36
37 \item {\vcode vmime::net::transport}: interface for a transport service.
38 A transport service is capable of sending messages. This is used for
39 SMTP and sendmail.
40
41 \item {\vcode vmime::net::session}: a session object is used to store the
42 parameters used by a service (eg. connection parameters). Each service
43 instance is associated with only one session. The session object is capable
44 of creating instances of services.
45 \end{itemize}
46
47 The following classes are specific to store services:
48
49 \begin{itemize}
50 \item {\vcode vmime::net::folder}: a folder can either contain other folders
51 or messages, or both.
52
53 \item {\vcode vmime::net::message}: this is the interface for dealing with
54 messages. For a given message, you can have access to its flags, its MIME
55 structure and you can also extract the whole message data or given parts (if
56 supported by the underlying protocol).
57 \end{itemize}
58
59
60 % ============================================================================
61 \section{Working with sessions}
62
63 \subsection{Setting properties} % --------------------------------------------
64
65 Sessions are used to store configuration parameters for services. They
66 contains a set of typed properties that can modify the behaviour of the
67 services. Before using a messaging service, you must create and
68 initialize a session object:
69
70 \begin{lstlisting}
71 vmime::shared_ptr <net::session> theSession = vmime::make_shared <net::session>();
72 \end{lstlisting}
73
74 Session properties include:
75
76 \begin{itemize}
77 \item connection parameters: host and port to connect to;
78 \item authentication parameters: user credentials required to use the
79 service (if any);
80 \item protocol-specific parameters: enable or disable extensions (eg. APOP
81 support in POP3).
82 \end{itemize}
83
84 Properties are stored using a dotted notation, to specify the service type,
85 the protocol name, the category and the name of the property:
86
87 \begin{verbatim}
88 {service_type}.{protocol}.category.name
89 \end{verbatim}
90
91 An example of property is \emph{store.pop3.options.apop} (used to enable or
92 disable the use of APOP authentication). The \emph{store.pop3} part is called
93 the \emph{prefix}. This allow specifying different values for the same
94 property depending on the protocol used.
95
96 The session properties are stored in a {\vcode vmime::propertySet} object.
97 To set the value of a property, you can use either:
98
99 \begin{lstlisting}
100 theSession->getProperties().setProperty("property-name", value);
101 \end{lstlisting}
102
103 or:
104
105 \begin{lstlisting}
106 theSession->getProperties()["property-name"] = value;
107 \end{lstlisting}
108
109
110 \subsection{Available properties} % ------------------------------------------
111
112 Following is a list of available properties and the protocols they apply to,
113 as the time of writing this documentation\footnote{You can get an up-to-date
114 list of the properties by running \vexample{Example7}}. For better clarity,
115 the prefixes do not appear in this table.
116
117 \begin{table}[!ht]
118 \noindent\begin{tabularx}{1.0\textwidth}{|l|c|X|c|c|c|c|c|c|c|c|}
119 \hline
120 {\bf Property name} &
121 {\bf Type} &
122 {\bf Description} &
123 \verti{\bf POP3} &
124 \verti{\bf POP3S} &
125 \verti{\bf IMAP} &
126 \verti{\bf IMAPS} &
127 \verti{\bf SMTP} &
128 \verti{\bf SMTPS} &
129 \verti{\bf maildir} &
130 \verti{\bf sendmail} \\
131 \hline
132 \hline
133 options.sasl & bool & Set to {\vcode true} to use SASL authentication, if
134 available. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
135 \hline
136 options.sasl.fallback & bool & Fail if SASL authentication failed (do not
137 try other authentication mechanisms). & \vdot & \vdot & \vdot & \vdot &
138 \vdot & \vdot & & \\
139 \hline
140 auth.username\footnote{You should use authenticators
141 instead.\label{fn_auth_username}} & string & Set the username of the account
142 to connect to. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
143 \hline
144 auth.password\footref{fn_auth_username} & string & Set the password of the
145 account. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
146 \hline
147 connection.tls & bool & Set to {\vcode true} to start a secured connection
148 using STARTTLS extension, if available. & \vdot & & \vdot & & \vdot & & & \\
149 \hline
150 connection.tls.required & bool & Fail if a secured connection cannot be
151 started. & \vdot & & \vdot & & \vdot & & & \\
152 \hline
153 server.address & string & Server host name or IP address. &\vdot & \vdot &
154 \vdot & \vdot & \vdot & \vdot & & \\
155 \hline
156 server.port & int & Server port. & \vdot & \vdot & \vdot & \vdot &
157 \vdot & \vdot & & \\
158 \hline
159 server.rootpath & string & Root directory for mail repository (eg.
160 \emph{/home/vincent/Mail}). & & & & & & & \vdot & \\
161 \hline
162 \end{tabularx}
163 \caption{Properties common to all protocols}
164 \end{table}
165
166 \newpage
167 These are the protocol-specific options:
168
169 \begin{table}[!ht]
170 \noindent\begin{tabularx}{1.0\textwidth}{|l|c|X|}
171 \hline
172 {\bf Property name} &
173 {\bf Type} &
174 {\bf Description} \\
175 % POP3/POP3S
176 \hline
177 \multicolumn{3}{|c|}{POP3, POP3S} \\
178 \hline
179 store.pop3.options.apop & bool & Enable or disable authentication with
180 APOP (if SASL is enabled, this occurs after all SASL mechanisms have been
181 tried). \\
182 \hline
183 store.pop3.options.apop.fallback & bool & If set to {\vcode true} and
184 APOP fails, the authentication process fails (ie. unsecure plain text
185 authentication is not used). \\
186 \hline
187 % SMTP
188 \multicolumn{3}{|c|}{SMTP, SMTPS} \\
189 \hline
190 transport.smtp.options.need-authentication & bool & Set to \emph{true} if
191 the server requires to authenticate before sending messages. \\
192 \hline
193 transport.smtp.options.pipelining & bool & Set to {\vcode false} to disable
194 command pipelining, if the server supports it (default is {\vcode true}). \\
195 \hline
196 transport.smtp.options.chunking & bool & Set to {\vcode false} to disable
197 CHUNKING extension, if the server supports it (default is {\vcode true}). \\
198 \hline
199 % sendmail
200 \multicolumn{3}{|c|}{sendmail} \\
201 \hline
202 transport.sendmail.binpath & string & The path to the \emph{sendmail}
203 executable on your system. The default is the one found by the configuration
204 script when VMime was built. \\
205 \hline
206 \end{tabularx}
207 \caption{Protocol-specific options}
208 \end{table}
209
210
211 \subsection{Instanciating services} % ----------------------------------------
212
213 You can create a service either by specifying its protocol name, or by
214 specifying the URL of the service. Creation by name is deprecated so
215 this chapter only presents the latter option.
216
217 The URL scheme for connecting to services is:
218
219 \begin{verbatim}
220 protocol://[username[:password]@]host[:port]/[root-path]
221 \end{verbatim}
222
223 \vnote{For local services (ie. \emph{sendmail} and \emph{maildir}), the host
224 part is not used, but it must not be empty (you can use "localhost").}
225
226 The following table shows an example URL for each service:
227
228 \noindent\begin{tabularx}{1.0\textwidth}{|c|X|}
229 \hline
230 {\bf Service} &
231 {\bf Connection URL} \\
232 \hline
233 imap, imaps & {\tt imap://imap.example.com},
234 {\tt imaps://vincent:pass@example.com} \\
235 \hline
236 pop3, pop3s & {\tt pop3://pop3.example.com} \\
237 \hline
238 smtp, smtps & {\tt smtp://smtp.example.com} \\
239 \hline
240 maildir & {\tt maildir://localhost/home/vincent/Mail} (host not used) \\
241 \hline
242 sendmail & {\tt sendmail://localhost} (host not used, always localhost) \\
243 \hline
244 \end{tabularx}
245
246 \newpage
247
248 When you have the connection URL, instanciating the service is quite simple.
249 Depending on the type of service, you will use either {\vcode getStore()} or
250 {\vcode getTransport()}. For example, for store services, use:
251
252 \begin{lstlisting}
253 vmime::utility:url url("imap://user:pass@imap.example.com");
254 vmime::shared_ptr <vmime::net::store> st = sess->getStore(url);
255 \end{lstlisting}
256
257 and for transport services:
258
259 \begin{lstlisting}
260 vmime::utility:url url("smtp://smtp.example.com");
261 vmime::shared_ptr <vmime::net::transport> tr = sess->getTransport(url);
262 \end{lstlisting}
263
264
265 % ============================================================================
266 \section{User credentials and authenticators}
267
268 Some services need some user credentials (eg. username and password) to open
269 a session. In VMime, user credentials can be specified in the session
270 properties or by using a custom authenticator (callback).
271
272 \begin{lstlisting}[caption={Setting user credentials using session
273 properties}]
274 vmime::shared_ptr <vmime::net::session> sess; // Suppose we have a session
275
276 sess->getProperties()["store.imap.auth.username"] = "vincent";
277 sess->getProperties()["store.imap.auth.password"] = "my-password";
278 \end{lstlisting}
279
280 Although not recommended, you can also specify username and password
281 directly in the connection URL,
282 ie: \emph{imap://username:password@imap.example.com/}. This works only for
283 services requiring an username and a password as user credentials, and no
284 other information.
285
286 Sometimes, it may not be very convenient to set username/password in the
287 session properties, or not possible (eg. extended SASL mechanisms) . That's
288 why VMime offers an alternate way of getting user credentials: the
289 {\vcode authenticator} object. Basically, an authenticator is an object that
290 can return user credentials on-demand (like a callback).
291
292 Currently, there are two types of authenticator in VMime: a basic
293 authenticator (class {\vcode vmime::security::authenticator}) and, if SASL
294 support is enabled, a SASL authenticator
295 (class {\vcode vmime::security::sasl::SASLAuthenticator}). Usually, you
296 should use the default implementations, or at least make your own
297 implementation inherit from them.
298
299 The following example shows how to use a custom authenticator to request
300 the user to enter her/his credentials:
301
302 \begin{lstlisting}[caption={A simple interactive authenticator}]
303 class myAuthenticator : public vmime::security::defaultAuthenticator
304 {
305 const string getUsername() const
306 {
307 std::cout << "Enter your username: " << std::endl;
308
309 vmime::string res;
310 std::getline(std::cin, res);
311
312 return res;
313 }
314
315 const string getPassword() const
316 {
317 std::cout << "Enter your password: " << std::endl;
318
319 vmime::string res;
320 std::getline(std::cin, res);
321
322 return res;
323 }
324 };
325 \end{lstlisting}
326
327 This is how to use it:
328
329 \begin{lstlisting}
330 // First, create a session
331 vmime::shared_ptr <vmime::net::session> sess =
332 vmime::make_shared <vmime::net::session>();
333
334 // Next, initialize a service which will use our authenticator
335 vmime::shared_ptr <vmime::net::store> st =
336 sess->getStore(vmime::utility::url("imap://imap.example.com"),
337 /* use our authenticator */ vmime::make_shared <myAuthenticator>());
338 \end{lstlisting}
339
340 \vnote{An authenticator object should be used with one and only one service
341 at a time. This is required because the authentication process may need to
342 retrieve the service name (SASL).}
343
344 Of course, this example is quite simplified. For example, if several
345 authentication mechanisms are tried, the user may be requested to enter the
346 same information multiple times. See {\vexample Example6} for a more complex
347 implementation of an authenticator, with caching support.
348
349 If you want to use SASL (ie. if \emph{options.sasl} is set to \emph{true}),
350 your authenticator must inherit from
351 {\vcode vmime::security::sasl::SASLAuthenticator} or
352 {\vcode vmime::security::sasl::defaultSASLAuthenticator}, even if you do not
353 use the SASL-specific methods {\vcode getAcceptableMechanisms()} and
354 {\vcode setSASLMechanism()}. Have a look at {\vexample Example6} to see an
355 implementation of an SASL authenticator.
356
357 \begin{lstlisting}[caption={A simple SASL authenticator}]
358 class mySASLAuthenticator : public vmime::security::sasl::defaultSASLAuthenticator
359 {
360 typedef vmime::security::sasl::SASLMechanism mechanism; // save us typing
361
362 const std::vector <vmime::shared_ptr <mechanism> > getAcceptableMechanisms
363 (const std::vector <vmime::shared_ptr <mechanism> >& available,
364 vmime::shared_ptr <mechanism> suggested) const
365 {
366 // Here, you can sort the SASL mechanisms in the order they will be
367 // tried. If no SASL mechanism is acceptable (ie. for example, not
368 // enough secure), you can return an empty list.
369 //
370 // If you do not want to bother with this, you can simply return
371 // the default list, which is ordered by security strength.
372 return defaultSASLAuthenticator::
373 getAcceptableMechanisms(available, suggested);
374 }
375
376 void setSASLMechanism(vmime::shared_ptr <mechanism> mech)
377 {
378 // This is called when the authentication process is going to
379 // try the specified mechanism.
380 //
381 // The mechanism name is in mech->getName()
382
383 defaultSASLAuthenticator::setSASLMechanism(mech);
384 }
385
386 // ...implement getUsername() and getPassword()...
387 };
388 \end{lstlisting}
389
390
391 % ============================================================================
392 \section{Using transport service}
393
394 You have two possibilities for giving message data to the service when you
395 want to send a message:
396
397 \begin{itemize}
398 \item either you have a reference to a message (type {\vcode vmime::message})
399 and you can simply call {\vcode send(msg)};
400 \item or you only have raw message data (as a string, for example), and you
401 have to call the second overload of {\vcode send()}, which takes additional
402 parameters (corresponding to message envelope);
403 \end{itemize}
404
405 The following example illustrates the use of a transport service to send a
406 message using the second method:
407
408 \begin{lstlisting}[caption={Using a transport service}]
409 const vmime::string msgData =
410 "From: me@example.org \r\n"
411 "To: you@example.org \r\n"
412 "Date: Sun, Oct 30 2005 17:06:42 +0200 \r\n"
413 "Subject: Test \r\n"
414 "\r\n"
415 "Message body";
416
417 // Create a new session
418 vmime::utility::url url("smtp://example.com");
419
420 vmime::shared_ptr <vmime::net::session> sess =
421 vmime::make_shared <vmime::net::session>();
422
423 // Create an instance of the transport service
424 vmime::shared_ptr <vmime::net::transport> tr = sess->getTransport(url);
425
426 // Connect it
427 tr->connect();
428
429 // Send the message
430 vmime::utility::inputStreamStringAdapter is(msgData);
431
432 vmime::mailbox from("me@example.org");
433 vmime::mailboxList to;
434 to.appendMailbox(vmime::make_shared <vmime::mailbox>("you@example.org"));
435
436 tr->send(
437 /* expeditor */ from,
438 /* recipient(s) */ to,
439 /* data */ is,
440 /* total length */ msgData.length());
441
442 // We have finished using the service
443 tr->disconnect();
444 \end{lstlisting}
445
446 \vnote{Exceptions can be thrown at any time when using a service. For better
447 clarity, exceptions are not caught here, but be sure to catch them in your own
448 application to provide error feedback to the user.}
449
450 If you use SMTP, you can enable authentication by setting some properties
451 on the session object ({\vcode service::setProperty()} is a shortcut for
452 setting properties on the session with the correct prefix):
453
454 \begin{lstlisting}
455 tr->setProperty("options.need-authentication", true);
456 tr->setProperty("auth.username", "user");
457 tr->setProperty("auth.password", "password");
458 \end{lstlisting}
459
460
461 % ============================================================================
462 \section{Using store service}
463
464 \subsection{Connecting to a store} % -----------------------------------------
465
466 The first basic step for using a store service is to connect to it. The
467 following example shows how to initialize a session and instanciate the
468 store service:
469
470 \begin{lstlisting}[caption={Connecting to a store service}]
471 // Create a new session
472 vmime::utility::url url("imap://vincent:password@imap:example.org");
473
474 vmime::shared_ptr <vmime::net::session> sess =
475 vmime::make_shared <vmime::net::session>();
476
477 // Create an instance of the transport service
478 vmime::shared_ptr <vmime::net::store> store = sess->getStore(url);
479
480 // Connect it
481 store->connect();
482 \end{lstlisting}
483
484 \vnote{{\vexample Example6} contains a more complete example for connecting
485 to a store service, with support for a custom authenticator.}
486
487 \subsection{Opening a folder} % ----------------------------------------------
488
489 You can open a folder using two different access modes: either in
490 \emph{read-only} mode (where you can only read message flags and contents), or
491 in \emph{read-write} mode (where you can read messages, but also delete them
492 or add new ones). When you have a reference to a folder, simply call the
493 {\vcode open()} method with the desired access mode:
494
495 \begin{lstlisting}
496 folder->open(vmime::net::folder::MODE_READ_WRITE);
497 \end{lstlisting}
498
499 \vnote{Not all stores support the \emph{read-write} mode. By default, if the
500 \emph{read-write} mode is not available, the folder silently fall backs on
501 the \emph{read-only} mode, unless the \emph{failIfModeIsNotAvailable} argument
502 to {\vcode open()} is set to true.}
503
504 Call {\vcode getDefaultFolder()} on the store to obtain a reference to the
505 default folder, which is usually the INBOX folder (where messages arrive when
506 they are received).
507
508 You can also open a specific folder by specifying its path. The following
509 example will open a folder named \emph{bar}, which is a child of \emph{foo}
510 in the root folder:
511
512 \begin{lstlisting}[caption={Opening a folder from its path}]
513 vmime::net::folder::path path;
514 path /= vmime::net::folder::path::component("foo");
515 path /= vmime::net::folder::path::component("bar");
516
517 vmime::shared_ptr <vmime::net::folder> fld = store->getFolder(path);
518 fld->open(vmime::net::folder::MODE_READ_WRITE);
519 \end{lstlisting}
520
521 \vnote{You can specify a path as a string as there is no way to get the
522 separator used to delimitate path components. Always use {\vcode operator/=}
523 or {\vcode appendComponent}.}
524
525 \vnote{Path components are of type {\vcode vmime::word}, which means that
526 VMime supports folder names with extended characters, not only 7-bit
527 US-ASCII. However, be careful that this may not be supported by the
528 underlying store protocol (IMAP supports it, because it uses internally a
529 modified UTF-7 encoding).}
530
531 \subsection{Fetching messages} % ---------------------------------------------
532
533 You can fetch some information about a message without having to download the
534 whole message. Moreover, folders support fetching for multiple messages in
535 a single request, for better performance. The following items are currently
536 available for fetching:
537
538 \begin{itemize}
539 \item {\bf envelope}: sender, recipients, date and subject;
540 \item {\bf structure}: MIME structure of the message;
541 \item {\bf content-info}: content-type of the root part;
542 \item {\bf flags}: message flags;
543 \item {\bf size}: message size;
544 \item {\bf header}: retrieve all the header fields of a message;
545 \item {\bf uid}: unique identifier of a message;
546 \item {\bf importance}: fetch header fields suitable for use with
547 {\vcode misc::importanceHelper}.
548 \end{itemize}
549
550 \vnote{Not all services support all fetchable items. Call
551 {\vcode getFetchCapabilities()} on a folder to know which information can be
552 fetched by a service.}
553
554 The following code shows how to list all the messages in a folder, and
555 retrieve basic information to show them to the user:
556
557 \begin{lstlisting}[caption={Fetching information about multiple messages}]
558 std::vector <ref <vmime::net::message> > allMessages =
559 folder->getMessages(vmime::net::messageSet::byNumber(1, -1));
560 // -1 is a special value to mean "the number of the last message in the folder"
561
562 folder->fetchMessages(allMessages,
563 vmime::net::fetchAttributes::FLAGS |
564 vmime::net::fetchAttributes::ENVELOPE);
565
566 for (unsigned int i = 0 ; i < allMessages.size() ; ++i)
567 {
568 vmime::shared_ptr <vmime::net::message> msg = allMessages[i];
569
570 const int flags = msg->getFlags();
571
572 std::cout << "Message " << i << ":" << std::endl;
573
574 if (flags & vmime::net::message::FLAG_SEEN)
575 std::cout << " - is read" << std::endl;
576 if (flags & vmime::net::message::FLAG_DELETED)
577 std::cout << " - is deleted" << std::endl;
578
579 vmime::shared_ptr <const vmime::header> hdr = msg->getHeader();
580
581 std::cout << " - sent on " << hdr->Date()->generate() << std::endl;
582 std::cout << " - sent by " << hdr->From()->generate() << std::endl;
583 }
584 \end{lstlisting}
585
586 IMAP supports fetching specific header fields of a message. Here is how to use
587 the {\vcode fetchAttributes} object to do it:
588
589 \begin{lstlisting}[caption={Using fetchAttributes object to fetch specific header fields of a message}]
590
591 // Fetch message flags and the "Received" and "X-Mailer" header fields
592 vmime::net::fetchAttributes fetchAttribs;
593 fetchAttribs.add(vmime::net::fetchAttributes::FLAGS);
594 fetchAttribs.add("Received");
595 fetchAttribs.add("X-Mailer");
596
597 folder->fetchMessages(allMessages, fetchAttribs);
598 \end{lstlisting}
599
600
601 \subsection{Extracting messages and parts}
602
603 To extract the whole contents of a message (including headers), use the
604 {\vcode extract()} method on a {\vcode vmime::net::message} object. The
605 following example extracts the first message in the default folder:
606
607 \begin{lstlisting}[caption={Extracting messages}]
608 // Get a reference to the folder and to its first message
609 vmime::shared_ptr <vmime::net::folder> folder = store->getDefaultFolder();
610 vmime::shared_ptr <vmime::net::message> msg = folder->getMessage(1);
611
612 // Write the message contents to the standard output
613 vmime::utility::outputStreamAdapter out(std::cout);
614 msg->extract(out);
615 \end{lstlisting}
616
617 Some protocols (like IMAP) also support the extraction of specific MIME parts
618 of a message without downloading the whole message. This can save bandwidth
619 and time. The method {\vcode extractPart()} is used in this case:
620
621 \begin{lstlisting}[caption={Extracting a specific MIME part of a message}]
622 // Fetching structure is required before extracting a part
623 folder->fetchMessage(msg, vmime::net::fetchAttributes::STRUCTURE);
624
625 // Now, we can extract the part
626 msg->extractPart(msg->getStructure()->getPartAt(0)->getPartAt(1));
627 \end{lstlisting}
628
629 Suppose we have a message with the following structure:
630
631 \begin{verbatim}
632 multipart/mixed
633 text/html
634 image/jpeg [*]
635 \end{verbatim}
636
637 The previous example will extract the header and body of the \emph{image/jpeg}
638 part.
639
640 \subsection{Deleting messages} % ---------------------------------------------
641
642 The following example will delete the second and the third message from the
643 store.
644
645 \begin{lstlisting}[caption={Deleting messages}]
646 vmime::shared_ptr <vmime::net::folder> folder = store->getDefaultFolder();
647
648 folder->deleteMessages(vmime::net::messageSet::byNumber(/* from */ 2, /* to */ 3));
649
650 // This is equivalent
651 std::vector <int> nums;
652 nums.push_back(2);
653 nums.push_back(3);
654 folder->deleteMessages(vmime::net::messageSet::byNumber(nums));
655
656 // This is also equivalent (but will require 2 roundtrips to server)
657 folder->deleteMessages(vmime::net::messageSet::byNumber(2));
658 folder->deleteMessages(vmime::net::messageSet::byNumber(2)); // renumbered, 3 becomes 2
659 \end{lstlisting}
660
661 \subsection{Events} % --------------------------------------------------------
662
663 As a result of executing some operation (or from time to time, even if no
664 operation has been performed), a store service can send events to notify you
665 that something has changed (eg. the number of messages in a folder). These
666 events may allow you to update the user interface associated to a message
667 store.
668
669 Currently, there are three types of event:
670
671 \begin{itemize}
672 \item {\bf message change}: sent when the number of messages in a folder
673 has changed (ie. some messages have been added or removed);
674 \item {\bf message count change}: sent when one or more message(s) have
675 changed (eg. flags or deleted status);
676 \item {\bf folder change}: sent when a folder has been created, renamed or
677 deleted.
678 \end{itemize}
679
680 You can register a listener for each event type by using the corresponding
681 methods on a {\vcode folder} object: {\vcode addMessageChangedListener()},
682 {\vcode addMessageCountListener()} or {\vcode addFolderListener()}. For more
683 information, please read the class documentation for
684 {\vcode vmime::net::events} namespace.
685
686
687 % ============================================================================
688 \section{Handling timeouts}
689
690 Unexpected errors can occur while messaging services are performing
691 operations and waiting a response from the server (eg. server stops
692 responding, network link falls down). As all operations as synchronous,
693 they can be ``blocked'' a long time before returning (in fact, they loop
694 until they either receive a response from the server, or the underlying
695 socket system returns an error).
696
697 VMime provides a mechanism to control the duration of operations. This
698 mechanism allows the program to cancel an operation that is currently
699 running.
700
701 An interface called {\vcode timeoutHandler} is provided:
702
703 \begin{lstlisting}
704 class timeoutHandler : public object
705 {
706 /** Called to test if the time limit has been reached.
707 *
708 * @return true if the timeout delay is elapsed
709 */
710 virtual const bool isTimeOut() = 0;
711
712 /** Called to reset the timeout counter.
713 */
714 virtual void resetTimeOut() = 0;
715
716 /** Called when the time limit has been reached (when
717 * isTimeOut() returned true).
718 *
719 * @return true to continue (and reset the timeout)
720 * or false to cancel the current operation
721 */
722 virtual const bool handleTimeOut() = 0;
723 };
724 \end{lstlisting}
725
726 While the operation runs, the service calls {\vcode isTimeout()} at variable
727 intervals. If the {\vcode isTimeout()} function returns {\vcode true},
728 then {\vcode handleTimeout()} is called. If the {\vcode handleTimeout()}
729 function returns {\vcode false}, the operation is cancelled and
730 an {\vcode operation\_timed\_out} exception is thrown. Else, if
731 {\vcode handleTimeout()} returns true, the operation continues and the
732 timeout counter is reset.
733 The function {\vcode resetTimeout()} is called each time data has
734 been received from the server to reset the timeout delay.
735
736 When using a service, a default timeout handler is set: if an operation
737 is blocked for more than 30 seconds (ie. network link is down and no data
738 was received since 30 seconds), an {\vcode operation\_timed\_out} exception
739 is thrown.
740
741 The following example shows how to implement a simple timeout handler:
742
743 \begin{lstlisting}[caption={Implementing a simple timeout handler}]
744 class myTimeoutHandler : public vmime::net::timeoutHandler
745 {
746 public:
747
748 myTimeoutHandler()
749 {
750 m_startTime = time(NULL);
751 }
752
753 const bool isTimeOut()
754 {
755 return (time(NULL) >= m_startTime + 30); // 30 seconds timeout
756 }
757
758 void resetTimeOut()
759 {
760 m_startTime = time(NULL);
761 }
762
763 const bool handleTimeOut()
764 {
765 std::cout << "Operation timed out." << std::endl;
766 << "Press [Y] to continue, or [N] to "
767 << "cancel the operation." << std::endl;
768
769 std::string response;
770 std::cin >> response;
771
772 return (response == "y" || response == "Y");
773 }
774
775 private:
776
777 time_t m_startTime;
778 };
779 \end{lstlisting}
780
781 To make the service use your timeout handler, you need to write a factory
782 class, to allow the service to create instances of the handler class. This
783 is required because the service can use several connections to the server
784 simultaneously, and each connection needs its own timeout handler.
785
786 \begin{lstlisting}
787 class myTimeoutHandlerFactory : public vmime::net::timeoutHandlerFactory
788 {
789 public:
790
791 ref <timeoutHandler> create()
792 {
793 return vmime::make_shared <myTimeoutHandler>();
794 }
795 };
796 \end{lstlisting}
797
798 Then, call the {\vcode setTimeoutHandlerFactory()} method on the service object
799 to set the timeout handler factory to use during the session:
800
801 \begin{lstlisting}
802 theService->setTimeoutHandlerFactory(vmime::make_shared <myTimeoutHandlerFactory>());
803 \end{lstlisting}
804
805
806 % ============================================================================
807 \newpage
808 \section{Secured connection using TLS/SSL}
809
810 \subsection{Introduction} % --------------------------------------------------
811
812 If you have enabled TLS support in VMime, you can configure messaging services
813 so that they use a secured connection.
814
815 Quoting from RFC-2246 - the TLS 1.0 protocol specification: \emph{`` The TLS
816 protocol provides communications privacy over the Internet. The protocol
817 allows client/server applications to communicate in a way that is designed
818 to prevent eavesdropping, tampering, or message forgery.''}
819
820 TLS has the following advantages:
821
822 \begin{itemize}
823 \item authentication: server identity can be verified;
824 \item privacy: transmission of data between client and server cannot be read
825 by someone in the middle of the connection;
826 \item integrity: original data which is transferred between a client and a
827 server can not be modified by an attacker without being detected.
828 \end{itemize}
829
830 \vnote{What is the difference between SSL and TLS? SSL is a protocol designed
831 by Netscape. TLS is a standard protocol, and is partly based on version 3 of
832 the SSL protocol. The two protocols are not interoperable, but TLS does
833 support a mechanism to back down to SSL 3.}
834
835 VMime offers two possibilities for using a secured connection:
836
837 \begin{itemize}
838 \item you can connect to a server listening on a special port (eg. IMAPS
839 instead of IMAP): this is the classical use of SSL, but is now deprecated;
840 \item connect to a server listening on the default port, and then begin a
841 secured connection: this is STARTTLS.
842 \end{itemize}
843
844
845 \subsection{Setting up a secured connection} % -------------------------------
846
847 \subsubsection{Connecting to a ``secured'' port} % ...........................
848
849 To use the classical SSL/TLS way, simply use the ``S'' version of the protocol
850 to connect to the server (eg. \emph{imaps} instead of \emph{imap}). This is
851 currently available for SMTP, POP3 and IMAP.
852
853 \begin{lstlisting}
854 vmime::shared_ptr <vmime::net::store> store =
855 theSession->getStore(vmime::utility::url("imaps://example.org"));
856 \end{lstlisting}
857
858 \subsubsection{Using STARTTLS} % .............................................
859
860 To make the service start a secured session using the STARTTLS method, simply
861 set the \emph{connection.tls} property:
862
863 \begin{lstlisting}
864 theService->setProperty("connection.tls", true);
865 \end{lstlisting}
866
867 \vnote{If, for some reason, a secured connection cannot be started, the
868 default behaviour is to fallback on a normal connection. To make
869 {\vcode connect()} fail if STARTTLS fails, set the
870 \emph{connection.tls.required} to \emph{true}.}
871
872 \subsection{Certificate verification} % --------------------------------------
873
874 \subsubsection{How it works} % ...............................................
875
876 If you tried the previous examples, a
877 {\vcode certificateException} might have been thrown.
878 This is because the default certificate verifier in VMime did not manage to
879 verify the certificate, and so could not trust it.
880
881 Basically, when you connect to a server using TLS, the server responds with
882 a list of certificates, called a certificate chain (usually, certificates are
883 of type X.509\footnote{And VMime currently supports only X.509 certificates}).
884 The certificate chain is ordered so that the first certificate is the subject
885 certificate, the second is the subject's issuer one, the third is the issuer's
886 issuer, and so on.
887
888 To decide whether the server can be trusted or not, you have to verify that
889 \emph{each} certificate is valid (ie. is trusted). For more information
890 about X.509 and certificate verification, see related articles on Wikipedia
891 \footnote{See \url{http://wikipedia.org/wiki/Public\_key\_certificate}}.
892
893 \subsubsection{Using the default certificate verifier} % .....................
894
895 The default certificate verifier maintains a list of root (CAs) and user
896 certificates that are trusted. By default, the list is empty. So, you have
897 to initialize it before using the verifier.
898
899 The algorithm\footnote{See
900 \url{http://wikipedia.org/wiki/Certification\_path\_validation\_algorithm}}
901 used is quite simple:
902
903 \begin{enumerate}
904 \item for every certificate in the chain, verify that the certificate has been
905 issued by the next certificate in the chain;
906 \item for every certificate in the chain, verify that the certificate is valid
907 at the current time;
908 \item ensure that the first certificate's subject name matches the hostname
909 of the server;
910 \item decide whether the subject's certificate can be trusted:
911 \begin{itemize}
912 \item first, verify that the the last certificate in the chain was
913 issued by a third-party that we trust (root CAs);
914 \item if the issuer certificate cannot be verified against root CAs,
915 compare the subject's certificate against the trusted certificates
916 (the certificates the user has decided to trust).
917 \end{itemize}
918 \end{enumerate}
919
920 First, we need some code to load existing X.509 certificates:
921
922 \begin{lstlisting}[caption={Reading a X.509 certificate from a file}]
923 vmime::shared_ptr <vmime::security::cert::X509Certificate>
924 loadX509CertificateFromFile(const std::string& path)
925 {
926 std::ifstream certFile;
927 certFile.open(path.c_str(), std::ios::in | std::ios::binary);
928
929 if (!certFile)
930 {
931 // ...handle error...
932 }
933
934 vmime::utility::inputStreamAdapter is(certFile);
935 vmime::shared_ptr <vmime::security::cert::X509Certificate> cert;
936
937 // Try DER format
938 cert = vmime::security::cert::X509Certificate::import
939 (is, vmime::security::cert::X509Certificate::FORMAT_DER);
940
941 if (cert != NULL)
942 return cert;
943
944 // Try PEM format
945 is.reset();
946 cert = vmime::security::cert::X509Certificate::import
947 (is, vmime::security::cert::X509Certificate::FORMAT_PEM);
948
949 return cert;
950 }
951 \end{lstlisting}
952
953 Then, we can use the {\vcode loadX509CertificateFromFile} function to load
954 certificates and initialize the certificate verifier:
955
956 \begin{lstlisting}[caption={Using the default certificate verifier}]
957 vmime::shared_ptr <vmime::security::cert::defaultCertificateVerifier> vrf =
958 vmime::make_shared <vmime::security::cert::defaultCertificateVerifier>();
959
960 // Load root CAs (such as Verisign or Thawte)
961 std::vector <vmime::shared_ptr <vmime::security::cert::X509Certificate> > rootCAs;
962
963 rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca1.cer");
964 rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca2.cer");
965 rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca3.cer");
966
967 vrf->setX509RootCAs(rootCAs);
968
969 // Then, load certificates that the user explicitely chose to trust
970 std::vector <vmime::shared_ptr <vmime::security::cert::X509Certificate> > trusted;
971
972 trusted.push_back(loadX509CertificateFromFile("/path/to/trusted-site1.cer");
973 trusted.push_back(loadX509CertificateFromFile("/path/to/trusted-site2.cer");
974
975 vrf->setX509TrustedCerts(trusted);
976 \end{lstlisting}
977
978
979 \subsubsection{Writing your own certificate verifier} % ......................
980
981 If you need to do more complex verifications on certificates, you will have to
982 write your own verifier. Your verifier should inherit from the
983 {\vcode vmime::security::cert::certificateVerifier} class and implement the
984 method {\vcode verify()}. Then, if the specified certificate chain is trusted,
985 simply return from the function, or else throw a
986 {\vcode certificateException}.
987
988 The following example shows how to implement an interactive certificate
989 verifier which relies on the user's decision, and nothing else (you SHOULD NOT
990 use this in a production application as this is obviously a serious security
991 issue):
992
993 \begin{lstlisting}[caption={A custom certificate verifier}]
994 class myCertVerifier : public vmime::security::cert::certificateVerifier
995 {
996 public:
997
998 void verify(vmime::shared_ptr <certificateChain> certs)
999 {
1000 // Obtain the subject's certificate
1001 vmime::shared_ptr <vmime::security::cert::certificate> cert = chain->getAt(0);
1002
1003 std::cout << std::endl;
1004 std::cout << "Server sent a '" << cert->getType() << "'"
1005 << " certificate." << std::endl;
1006 std::cout << "Do you want to accept this certificate? (Y/n) ";
1007 std::cout.flush();
1008
1009 std::string answer;
1010 std::getline(std::cin, answer);
1011
1012 if (answer.length() != 0 && (answer[0] == 'Y' || answer[0] == 'y'))
1013 return; // OK, we trust the certificate
1014
1015 // Don't trust this certificate
1016 throw vmime::security::cert::certificateException();
1017 }
1018 };
1019 \end{lstlisting}
1020
1021 \vnote{In production code, it may be a good idea to remember user's decisions
1022 about which certificates to trust and which not. See {\vexample Example6} for
1023 a basic cache implementation.}
1024
1025 Finally, to make the service use your own certificate verifier, simply write:
1026
1027 \begin{lstlisting}
1028 theService->setCertificateVerifier(vmime::make_shared <myCertVerifier>());
1029 \end{lstlisting}
1030
1031 \subsection{SSL/TLS Properties} % --------------------------------------------
1032
1033 If you want to customize behavior or set some options on TLS/SSL connection,
1034 you may use the TLSProperties object, and pass it to the service session. The
1035 TLS/SSL options must be set {\em before} creating any service with the session
1036 (ie. before calling either {\vcode getStore()} or {\vcode getTransport()} on
1037 the session), or they will not be used.
1038
1039 The following example shows how to set the cipher suite preferences for TLS:
1040
1041 \begin{lstlisting}[caption={Setting TLS cipher suite preferences}]
1042 vmime::shared_ptr <vmime::net::session> sess = /* ... */;
1043
1044 vmime::shared_ptr <vmime::net::tls::TLSProperties> tlsProps =
1045 vmime::make_shared <vmime::net::tls::TLSProperties>();
1046
1047 // for OpenSSL
1048 tlsProps->setCipherString("HIGH:!ADH:@STRENGTH");
1049
1050 // for GNU TLS
1051 tlsProps->setCipherString("NORMAL:%SSL3_RECORD_VERSION");
1052
1053 sess->setTLSProperties(tlsProps);
1054 \end{lstlisting}
1055
1056 Please note that the cipher suite string format and meaning depend on the
1057 underlying TLS library (either OpenSSL or GNU TLS):
1058
1059 \begin{itemize}
1060 \item for GNU TLS, read this: \newline
1061 \url{http://gnutls.org/manual/html\_node/Priority-Strings.html}
1062
1063 \item for OpenSSL, read this: \newline
1064 \url{http://www.openssl.org/docs/apps/ciphers.html#CIPHER\_STRINGS}
1065 \end{itemize}
1066
1067 You may also set cipher suite preferences using predefined constants that
1068 map to generic security modes:
1069
1070 \begin{lstlisting}[caption={Setting TLS cipher suite preferences using predefined modes}]
1071 sess->setCipherSuite(vmime::net::tls::TLSProperties::CIPHERSUITE_HIGH);
1072 \end{lstlisting}
1073
1074 The following constants are available:
1075
1076 \noindent\begin{tabularx}{1.0\textwidth}{|l|X|}
1077 \hline
1078 {\bf Constant} &
1079 {\bf Meaning} \\
1080 \hline
1081 CIPHERSUITE\_HIGH &
1082 High encryption cipher suites ($>$ 128 bits) \\
1083 \hline
1084 CIPHERSUITE\_MEDIUM &
1085 Medium encryption cipher suites ($>=$ 128 bits) \\
1086 \hline
1087 CIPHERSUITE\_LOW &
1088 Low encryption cipher suites ($>=$ 64 bits) \\
1089 \hline
1090 CIPHERSUITE\_DEFAULT &
1091 Default cipher suite (actual cipher suites used depends
1092 on the underlying SSL/TLS library) \\
1093 \hline
1094 \end{tabularx}
1095