Binc IMAP logo Binc IMAP - Technical Documentation
GNU General Public License
Andreas Aardal Hanssen <andreas@hanssen.name>

Binc in my home area, IMAPdir and cousins

Binc IMAP uses either Maildir++ or a structure called IMAPdir to store its set of mailboxes. IMAPdir is more or less similar to Maildir++, but it provides more flexibility with regards to mailbox names and hierarchy structure.

In a sense, IMAPdir takes all the goods from Maildir and adds root level mailboxes, submailboxes both of regular root level mailboxes and of the special mailbox INBOX, mail in mailboxes of any level, and with no restrictions.

In the root of the IMAPdir structure, Binc IMAP stores the list of a user's subscribed folders in a file called bincimap-subscribed. This file should only be edited manually if you are confident with Binc::Storage. Normally the administrator and the IMAP user will leave this to Binc IMAP.

Binc IMAP's Maildir backend (default) will temporarily create a lock file called bincimap-scan-lock inside a Maildir when it is scanning for mailbox changes and delegating unique message identifiers. This is to ensure that UIDs are delegated exactly once to every message that has been detected by any one Binc IMAP server instance.

Inside each Maildir, Binc IMAP stores two files that allow multiple instances of the server to communicate the state and changes of the mailbox: bincimap-uidvalidity and bincimap-cache. These files are safe to delete, although that will trigger UIDVALIDITY to bounce and clients may have to resynchronize their local state.

Object Oriented Design: Brokers, Depots, Operators.

Binc IMAP's design is simple and modular. This makes it easy to maintain and extend.

Although the IMAP protocol is relatively complex, you will find that Binc IMAP's solution is surprisingly easy to grasp.

At the heart of Binc IMAP's implementation lies the basic functionality for Object Oriented Design provided by the ISO C++ standard and general knowledge in the area of standard Design Patterns.

The main components are:

Binc IMAP, Object Oriented Design

Broker

One Broker holds a set of Operators. For each state Binc IMAP is in, the BrokerFactory delegates exactly one Broker to hold the relevant Operator objects.

Typically, an Operator can be assigned to more than one Broker. For example, the Operator that serves the IMAP command "NOOP" (a command that is available in all three IMAP states), NoopOperator, is available in all Broker objects.

The Broker is responsible for first passing the Depot and the IO singleton to the appropriate Operator, generating a Command object.

The Broker is also responsible for passing the resulting Command object to the Operator together with the Depot, generating the untagged responses that come as a result of the processing.


Broker *broker = BrokerFactory.getBroker(STATE_SELECTED);
if (broker != NULL)
  throw CriticalException("no broker for selected state");

Command command;

try {
  broker.parse(com, command);
  broker.process(depot, command);
} catch (...
        

BrokerFactory

The BrokerFactory manages the Broker objects.

Given a state, the BrokerFactory provides a Broker that holds all the Operator objects available to the client.

This provides a modular and safe separation of the priviledges available at the different states in the IMAP session.

The preauthenticate stub has a BrokerFactory that can only generate Broker objects for the non-authenticated state.


Command

A Command object holds all information that was passed to the Operator that served a specific IMAP command.

Command objects are named. Examples of such names are "CHECK", "SUBSCRIBE" and "LOGOUT".

For the name "FETCH", the Command object is decorated with sequence set, optionally a section and so on. The parse() method in each Operator is responsible for decorating the Command object.

The Command object is short-lived. It is created, decorated, passed on to the Operator, then discarded.


Depot

A Depot is responsible for handling the different Mailbox objects, and it is the mailbox structure authority.

Given an IMAP mailbox path as input, a Depot can give the caller a corresponding Mailbox object if it finds one that successfully identifies the type of Mailbox.

The Depot is also aware of what the default Mailbox type object is. This Mailbox object is used when creating new IMAP mailboxes.

Finally, the Depot is used to translate mailbox names to a representation on the file system and back. There are currently two specializations of the Depot object available: one for Maildir++ and one for IMAPdir. Each has its own characteristics in how do translate the mailbox hierarchy to the file system.

Mailbox *mailbox = depot.getDefaultMailbox();
if (mailbox == NULL)
  throw CriticalException("no default mailbox provided");

try {
  mailbox->imapCreate("work/2003/07/todo");
} catch (...
        

DepotFactory

The DepotFactory manages the Depot objects.

New Depot objects are assigned to the DepotFactory in runtime. This makes it easy to add new Depot objects using loadable modules. The Depot objects are registered and accessed via their names, such as "Maildir++" or "IMAPdir".

The DepotFactory gives individual users of Binc IMAP the option to choose the Depot object that suits their needs the best.


IO

The IO is a global. It consists of two instances - com and logger.

com reads and writes characters to and from the client, and hides the optional SSL encryption.

logger writes characters to Binc IMAP's log files. It hides the method used to log data. Currently it supports logging to stderr and syslog.


Mailbox

The Mailbox is an abstract for Binc IMAP's different backends. Bundled with Binc is a backend for Maildir. The class Maildir inherits Mailbox.

In short, a Mailbox contains all methods needed for Binc IMAP to serve a specific backend. It also holds a method to identify a Mailbox of its own kind.

All registered Mailbox objects are held by the Depot.


Mailbox *mailbox = depot.getSelectedMailbox();
if (mailbox == NULL)
  throw CriticalException("no selected mailbox in selected state");

mailbox->imapExpunge();
mailbox->imapClose();
        

Operator

An Operator is associated with an IMAP command such as "SEARCH" or "AUTHENTICATE". In short, the Operator is used to perform an arbitrary operation on a Mailbox.

Typically, an Operator can be assigned to one or more Broker objects.

Operators contain, among others, the two public methods: parse() and process().

When given the IO singleton as input, the parse() method generates a Command object. This object can then be fed to process() together with a Depot.

When processing its command, an Operator is allowed to generate untagged responses and it can also update the state of a Mailbox, the Depot or the Session singleton.

Operator objects are assigned dynamically to each Broker, making it very easy to write extensions that add or replace existing Operator objects using Binc IMAP's loadable module support.


Session

The Session is a singleton object that holds information that is relevant to the current IMAP session.

Currently, the Session contains information about:

  • Global configuration (administrator settings)
  • Local configuration (user settings)
  • Command line arguments
  • Folder subscription list

Last updated on 2003-03-20.

Please direct comments on this document to the Binc IMAP mailing list. Remember to search the archives first.

Valid HTML 4.01! Powered by djbdns! Powered by Binc IMAP






































style with only LF. The MaildirMessage is an implementation of Message used in Maildir. When using a Maildir mailbox, Mailbox::iterator will return a reference to a MaildirMessage. MaildirMessage also uses a MaildirMessageCache singleton to handle cacheing of messages.

Although the inside of MaildirMessage both deals with files, cacheing and MIME, the Operator needs not think about this.


Operator

An Operator is associated with an IMAP command such as "SEARCH" or "AUTHENTICATE". In short, the Operator is used to perform an arbitrary operation on a Mailbox.

Typically, an Operator can be assigned to one or more Broker objects.

Operators contain, among others, the two public methods: parse() and process().

The parse() method decorates a Request object. This object can then be fed to process() together with a Depot.

When processing its request, an Operator is allowed to generate untagged responses and it can also update the state of a Mailbox, the Depot or the Session singleton.

Operator objects are assigned dynamically to each Broker, making it very easy to write extensions that add or replace existing Operator objects using Binc IMAP's loadable module support.


Session

The Session is a singleton object that holds information that is relevant to the current IMAP session.

Currently, the Session contains information about:


Last updated on 2003-07-31.

Please direct comments on this document to the Binc IMAP mailing list. Remember to search the archives first.

Valid HTML 4.01! Powered by djbdns! Powered by Binc IMAP