## The &Camel; Messaging Library

Jeffrey
Stedfast

    	    fejj@helixcode.com

Michael
Zucchi

    	    notzed@helixcode.com

Dan
Winship

    	    danw@helixcode.com

Bertrand
Guiheneuf

    	    bertrand@helixcode.com

2000, 2001
Ximian, Inc.

## Introduction

&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.

&Camel;'s initial design is heavily based on Sun's JavaMail 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.

&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.

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.

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.

## Overview

To begin using &Camel;, an application first creates subclassed `CamelSession` object. This object is used to store application defaults, and to coordinate communication between providers and the application.

A `CamelProvider` is a dynamically-loadable module that provides functionality associated with a specific service. Examples of providers are POP, IMAP and SMTP. Providers include subclasses of the various other &Camel; classes for accessing and manipulating messages.

`CamelService` is an abstract class for describing a connection to a local or remote service. It currently has two subclasses: `CamelStore`, for services that store messages (such as IMAP servers and mbox files), and `CamelTransport`, 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.

A `CamelStore` contains some number of `CamelFolder` objects, which in turn contain messages. A `CamelFolder` provides a `CamelFolderSummary` 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 `CamelMedium`.

Email messages are represented by the `CamelMimeMessage` class, a subclass of `CamelMedium`. This class includes operations for accessing RFC822 and MIME headers, accessing subparts of MIME messages, encoding and decoding Base64 and Quoted-Printable, etc.

`CamelTransport` includes methods for delivering messages. While the abstract `CamelTransport::send` method takes a `CamelMedium`, its subclasses may only be able to deliver messages of specific `CamelMedium` subclasses. For instance, `CamelSendmailTransport` requires a `CamelMimeMessage`, because it needs a message that includes a "To:" header. A hypothetical `CamelNNTPTransport` would need a `CamelNewsMessage`, which would have a "Newsgroups:" header.

The content of messages are referred to using `CamelStream` and its subclasses. In the case of an mbox-based store, the `CamelStream` would abstract the operation of reading the correct section of the mbox file. For IMAP, reading off the `CamelStream` might result in commands being issued to the remote IMAP server and data being read off a socket.

The final major class in &Camel; is `CamelException`, which is used to propagate information about errors. Many methods take a `CamelException` 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.

## Major Subcomponents

### The Message Store

A `CamelStore` inherits the ability to connect and authenticate to a service from its parent class, `CamelService`. It then adds the ability to retrieve folders. A store must contain at least one folder, which can be retrieved with `CamelStore::get_default_folder`. There are also methods to retrieve the "top-level" folder (for hieararchical stores), and to retrieve an arbitrary folder by name.

All `CamelFolder`s must implement certain core operations, most notably generating a summary and retrieving and deleting messages. A `CamelFolder` must assign a permanently unique identifier to each message it contains. Messages can then be retrieved via `CamelFolder::get_message`.

Folders must also implement the `get_parent_folder` and `list_subfolders` 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).

Folders that support searching can define the `search_by_expression` 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.

### Messages

As mentioned before, messages are represented by subclasses of `CamelMedium`. `CamelMedium` itself is a subclass of `CamelDataWrapper`, a generic class for connecting a typed data source to a data sink. `CamelMedium` adds the concept of message headers versus message body. (`CamelDataWrapper` has one other important subclass, `CamelMultipart`, which is used to provide separate access to the multiple independent parts of a multipart MIME type.) `CamelMedium`'s subclasses provide more specialized handling of various headers: `CamelMimePart` adds special handling for the &ldquot;Content-*&rdquot; headers in MIME messages, and its subclass `CamelMimeMessage` adds handling for the RFC822 headers.

Consider a message with two parts: a text part (in both plain text and HTML), and an attached image:

    	  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--

In &Camel;, this would be represented as follows:

### Streams

Streams are a generic data transport layer. Two basic stream classes are `CamelStreamFs`, for reading and writing files, and `CamelStreamMem`, for reading from and writing to objects that are already in memory.

Streams can also be filtered. So a CamelMimePart containing base64-encoded data can filter its output through CamelMimeFilterBasic. Other parts of the application that want to read its data will never need to even realize that the original data was encoded.