340 lines
12 KiB
Plaintext
340 lines
12 KiB
Plaintext
<!doctype article PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
|
<!entity Evolution "<application>Evolution</application>">
|
|
<!entity Camel "Camel">
|
|
]>
|
|
|
|
<article class="whitepaper" id="camel">
|
|
|
|
<artheader>
|
|
<title>The &Camel; Messaging Library</title>
|
|
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Dan</firstname>
|
|
<surname>Winship</surname>
|
|
<affiliation>
|
|
<address>
|
|
<email>danw@helixcode.com</email>
|
|
</address>
|
|
</affiliation>
|
|
</author>
|
|
|
|
<author>
|
|
<firstname>Bertrand</firstname>
|
|
<surname>Guiheneuf</surname>
|
|
<affiliation>
|
|
<address>
|
|
<email>bertrand@helixcode.com</email>
|
|
</address>
|
|
</affiliation>
|
|
</author>
|
|
</authorgroup>
|
|
|
|
<copyright>
|
|
<year>2000</year>
|
|
<holder>Helix Code, Inc.</holder>
|
|
</copyright>
|
|
|
|
</artheader>
|
|
|
|
<sect1 id="introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>
|
|
&Camel; is a generic messaging library. It is being used as the
|
|
back end for the mail component of &Evolution;. The name
|
|
"&Camel;" is an acronym; it refers to the fact that the
|
|
library is capable of going several days without food or water.
|
|
It means : Camel's Acronym Makes Everyone Laugh.
|
|
</para>
|
|
|
|
<para>
|
|
&Camel;'s initial design is heavily based on Sun's
|
|
<trademark>JavaMail</trademark> API. It uses the Gtk+ object
|
|
system, and many of its classes are direct analags of JavaMail
|
|
classes. Its design has also been influenced by the features of
|
|
IMAP, and the limitations of the standard UNIX mbox mail store,
|
|
which set some of the boundaries on its requirements and
|
|
extensibility.
|
|
</para>
|
|
|
|
<para>
|
|
&Camel; sees all message repositories as stores containing
|
|
folders. These folders in turn contain the messages the client
|
|
actually accesses. The use of such a unified interface allows
|
|
the client applications to be very extensible. &Camel; includes
|
|
an external provider mechanism which allows applications to
|
|
dynamically load and use protocols which were not available when
|
|
the application was initially written.
|
|
</para>
|
|
|
|
<para>
|
|
The abstract store/folder mechanism is a powerful and versatile
|
|
way of accessing messages. No particular asumptions are made on
|
|
the client side, thus allowing new ways of managing the
|
|
messages. For example, the messages stored in the folders don't
|
|
necessarily have to share some common physical location. The
|
|
folder can be a purely virtual folder, containing only
|
|
references to the actual messages. This is used by the "vFolder"
|
|
provider, which allows you select messages meeting particular
|
|
criteria and deal with them as a group.
|
|
</para>
|
|
|
|
<para>
|
|
In addition to these possibilities, &Camel; has full MIME
|
|
support. &Camel; MIME messages are lightweight objects
|
|
representing the MIME skeleton of the actual message. The data
|
|
contained in the subparts are never stored in memory except when
|
|
they are actually needed. The application, when accessing the
|
|
various MIME objects contained in the message (text parts,
|
|
attachments, embedded binary objects ...) asks &Camel; for a
|
|
stream that it can read data from. This scheme is particularly
|
|
useful with the IMAP provider. IMAP has strong MIME support
|
|
built-in, which allows &Camel; to download only the parts of
|
|
messages that it actually needs: attachments need not be
|
|
downloaded until they are viewed, and unnecessary
|
|
"multipart/alternative" parts will never be read off the server.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="overview">
|
|
<title>Overview</title>
|
|
|
|
<graphic format="gif" fileref="camel"></graphic>
|
|
|
|
<para>
|
|
To begin using &Camel;, an application first creates a
|
|
<classname>CamelSession</classname> object. This object is used
|
|
to store application defaults, and to coordinate communication
|
|
between providers and the application.
|
|
</para>
|
|
|
|
<para>
|
|
A <classname>CamelProvider</classname> is a dynamically-loadable
|
|
module that provides functionality associated with a specific
|
|
service. Examples of providers are IMAP and SMTP. Providers
|
|
include subclasses of the various other &Camel; classes for
|
|
accessing and manipulating messages.
|
|
</para>
|
|
|
|
<para>
|
|
<classname>CamelService</classname> is an abstract class for
|
|
describing a connection to a local or remote service. It
|
|
currently has two subclasses: <classname>CamelStore</classname>,
|
|
for services that store messages (such as IMAP servers and mbox
|
|
files), and <classname>CamelTransport</classname>, for services
|
|
that deliver messages (such as SMTP, or a local MTA). A provider
|
|
could also be both a store and a transport, as in the case of
|
|
NNTP.
|
|
</para>
|
|
|
|
<para>
|
|
A <classname>CamelStore</classname> contains some number of
|
|
<classname>CamelFolder</classname> objects, which in turn
|
|
contain messages. A <classname>CamelFolder</classname> provides
|
|
a <classname>CamelFolderSummary</classname> object, which
|
|
includes details about the subject, date, and sender of each
|
|
message in the folder. The folder also includes the messages
|
|
themselves, as subclasses of <classname>CamelMedium</classname>.
|
|
</para>
|
|
|
|
<para>
|
|
Email messages are represented by the
|
|
<classname>CamelMimeMessage</classname> class, a subclass of
|
|
<classname>CamelMedium</classname>. This class includes
|
|
operations for accessing RFC822 and MIME headers, accessing
|
|
subparts of MIME messages, encoding and decoding Base64 and
|
|
Quoted-Printable, etc.
|
|
</para>
|
|
|
|
<para>
|
|
<classname>CamelTransport</classname> includes methods for
|
|
delivering messages. While the abstract
|
|
<function>CamelTransport::send</function> method takes a
|
|
<classname>CamelMedium</classname>, its subclasses may only be
|
|
able to deliver messages of specific
|
|
<classname>CamelMedium</classname> subclasses. For instance,
|
|
<classname>CamelSendmailTransport</classname> requires a
|
|
<classname>CamelMimeMessage</classname>, because it needs a
|
|
message that includes a "To:" header. A hypothetical
|
|
<classname>CamelNNTPTransport</classname> would need a
|
|
<classname>CamelNewsMessage</classname>, which would have a
|
|
"Newsgroups:" header.
|
|
</para>
|
|
|
|
<para>
|
|
The content of messages are referred to using
|
|
<classname>CamelStream</classname> and its subclasses. In the
|
|
case of an mbox-based store, the
|
|
<classname>CamelStream</classname> would abstract the operation
|
|
of reading the correct section of the mbox file. For IMAP,
|
|
reading off the <classname>CamelStream</classname> might result
|
|
in commands being issued to the remote IMAP server and data
|
|
being read off a socket.
|
|
</para>
|
|
|
|
<para>
|
|
The final major class in &Camel; is
|
|
<classname>CamelException</classname>, which is used to
|
|
propagate information about errors. Many methods take a
|
|
<classname>CamelException</classname> as an argument, which the
|
|
caller can then check if an error occurs. It includes both a
|
|
numeric error code which can be interpreted by the program, and
|
|
a text error message that can be displayed to the user.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="classes">
|
|
<title>Major Subcomponents</title>
|
|
|
|
<sect2 id="store">
|
|
<title>The Message Store</title>
|
|
|
|
<para>
|
|
A <classname>CamelStore</classname> inherits the ability to
|
|
connect and authenticate to a service from its parent class,
|
|
<classname>CamelService</classname>. It then adds the ability
|
|
to retrieve folders. A store must contain at least one folder,
|
|
which can be retrieved with
|
|
<function>CamelStore::get_default_folder</function>. There are
|
|
also methods to retrieve the "top-level" folder (for
|
|
hieararchical stores), and to retrieve an arbitrary folder by
|
|
name.
|
|
</para>
|
|
|
|
<para>
|
|
All <classname>CamelFolder</classname>s must implement certain
|
|
core operations, most notably generating a summary and
|
|
retrieving and deleting messages. A
|
|
<classname>CamelFolder</classname> must assign a permanently
|
|
unique identifier to each message it contains. Messages can
|
|
then be retrieved via
|
|
<function>CamelFolder::get_message_by_uid</function>. Alternately,
|
|
within a single mail-reading session, messages can be referred
|
|
to by their linear position within the store using
|
|
<function>CamelFolder::get_message_by_number</function>.
|
|
</para>
|
|
|
|
<para>
|
|
Folders must also implement the
|
|
<function>get_parent_folder</function> and
|
|
<function>list_subfolders</function> methods. For stores that
|
|
don't allow multiple folders, they would return NULL and an
|
|
empty list, respectively. Stores that do allow multiple
|
|
folders will also define methods for creating and deleting
|
|
folders, and for moving messages between them (assuming the
|
|
folders are writable).
|
|
</para>
|
|
|
|
<para>
|
|
Folders that support searching can define the
|
|
<function>search_by_expression</function> method. For mbox
|
|
folders, this is implemented by indexing the messages with the
|
|
ibex library and using that to search them later. For IMAP
|
|
folders, this uses the IMAP SEARCH command. Other folder types
|
|
might not be able to implement this functionality, in which
|
|
case users would not be able to do full-content searches on
|
|
them.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="messages">
|
|
<title>Messages</title>
|
|
|
|
<para>
|
|
As mentioned before, messages are represented by subclasses of
|
|
<classname>CamelMedium</classname>.
|
|
<classname>CamelMedium</classname> itself is a subclass of
|
|
<classname>CamelDataWrapper</classname>, a generic class for
|
|
connecting a typed data source to a data sink.
|
|
<classname>CamelMedium</classname> adds the concept of message
|
|
headers versus message body.
|
|
(<classname>CamelDataWrapper</classname> has one other
|
|
important subclass, <classname>CamelMultipart</classname>,
|
|
which is used to provide separate access to the multiple
|
|
independent parts of a multipart MIME type.)
|
|
<classname>CamelMedium</classname>'s subclasses provide more
|
|
specialized handling of various headers:
|
|
<classname>CamelMimePart</classname> adds special handling for
|
|
the &ldquot;Content-*&rdquot; headers in MIME messages, and
|
|
its subclass <classname>CamelMimeMessage</classname> adds
|
|
handling for the RFC822 headers.
|
|
</para>
|
|
|
|
<graphic format="gif" fileref="mimemessage"></graphic>
|
|
|
|
<para>
|
|
Consider a message with two parts: a text part (in both plain
|
|
text and HTML), and an attached image:
|
|
|
|
<programlisting>
|
|
|
|
From: Dan Winship <danw@helixcode.com>
|
|
To: Matt Loper <matt@helixcode.com>
|
|
Subject: the Camel white paper
|
|
MIME-Version: 1.0
|
|
Content-Type: multipart/mixed;
|
|
boundary="jhTYrnsRrdhDFGa"
|
|
|
|
This is a multi-part message in MIME format.
|
|
--jhTYrnsRrdhDFGa
|
|
Content-Type: multipart/alternative;
|
|
boundary="sFSenbAFDSgDfg"
|
|
|
|
--sFSenbAFDSgDfg
|
|
Content-Type: text/plain
|
|
|
|
Hey, Matt
|
|
|
|
Check out this graphic...
|
|
|
|
-- Dan
|
|
|
|
--sFSenbAFDSgDfg
|
|
Content-Type: text/html
|
|
|
|
Hey, Matt<br>
|
|
<br>
|
|
Check out this graphic...<br>
|
|
<br>
|
|
-- Dan<br>
|
|
<br>
|
|
--sFSenbAFDSgDfg--
|
|
|
|
--jhTYrnsRrdhDFGa
|
|
Content-Type: image/png
|
|
Content-Transfer-Encoding: base64
|
|
|
|
F4JLw0ORrkRa8AwAMQJLAaI3UDIGsco9RAaB92...
|
|
--jhTYrnsRrdhDFGa--
|
|
</programlisting>
|
|
|
|
<para>
|
|
In &Camel;, this would be represented as follows:
|
|
</para>
|
|
|
|
<graphic fileref="samplemsg"></graphic>
|
|
</sect2>
|
|
|
|
<sect2 id="streams">
|
|
<title>Streams</title>
|
|
|
|
<para>
|
|
Streams are a generic data transport layer. Two basic stream
|
|
classes are <classname>CamelStreamFs</classname>, for
|
|
reading and writing files, and
|
|
<classname>CamelStreamMem</classname>, for reading from and
|
|
writing to objects that are already in memory.
|
|
</para>
|
|
|
|
<para>
|
|
Streams can also be chained together. So a CamelMimePart
|
|
containing base64-encoded data can filter its output through
|
|
a CamelStreamB64. Other parts of the application that want
|
|
to read its data will never need to even realize that the
|
|
original data was encoded.
|
|
</para>
|
|
</sect2>
|
|
|
|
</article>
|