5.  Mail Formatter

The mail formatter plugin will invoke plugin code to format any part of an email based on mime-type. There are several formatters used internally by the mailer for different contexts, and each can be hooked into separately, providing extensible mail formatting for everything from the primary mail display, to printing, to reply quoting and more. If you are implementing a handler for a given mime-type, each formatter appropriate for the data-type should be hooked into, so that it displays properly in all contexts.

Since the management object in this case is the same formatting object as used by the core mail display engine, a plugin may override or reimplement complete new functionality seamlessly.

This plugin hook isn't strictly part of the core functionality as it is provided only by the mail component. It however demonstrates that the plugin system is extensible itself.

5.1. Defining a formatter hook

Not sure if this fits here as such. Probably temporary placeholder.

	    
<hook class="com.novell.evolution.mail.format:1.0">
 <group id="formatter type">
  <item
    flags="handler flags"
    mime_type="major/minor"
    format="function spec"/> +
 </group> +
</hook>
id
The actual formatter this applies to. e.g. EMFormat for the base formatter class, EMFormatHTML for HTML output to a GtkHTML object, etc.
flags
Flags to define whether this is an attachment or inline content.
id
The name of the event to listen to.
mime_type
The type of object this handler formats.
format
A plugin-type specific function specification. This function will be invoked to format objects of the specified mime_type.

5.2. The formatting process

The formatting process is driven by the EMFormat object, although there are different subclasses of this object used for different purposes. These behave quite differently so each must be explained separately. There is the basic formatter type which converts a CamelMimeMessage into a stream of data, and there is a HTML formatter type which uses a GtkHTML object to parse the content and may request further information required to complete the formatting.

A basic formatter goes through the following steps:

  1. Outputs pre-amble information. e.g. Flag-For-Followup status.
  2. Invokes format_message to begin the message formatting. format_message displays the message header, then looks up the content object.
  3. Using the mime-type of the content object (whether supplied or calculated), a handler is looked up from a per-class table to process the type.
  4. If no handler exists, then the data is formatted as an attachment.
  5. If a handler exists, then it is invoked to display that type. Depending on whether the data is to be displayed 'inline' or not, the data may also get an attachment expander and button.
  6. The handler transforms the part's data, if need be, and writes the appropriate format output to a stream.

For conglomerate types, the formatting process is continued recursively, until all parts have been displayed, as appropriate.

A HTML formatter goes through the same basic steps, but has additional features and requirements. It uses multiple threads. At least one other thread is used for all of the Camel message content operations since some of them may block on remote I/O. This also simplifies cancellation processing. Also, because it has access to a full HTML rendering object, references to embedded content (images, buttons, etc.) are also processed.

Most format handlers don't need to know about all the fiddly details however. If they are just outputting HTML content with no out of band references, they work identical to the basic format handlers with the exception they cannot call any Gtk GUI code because of threading issues. This can still be done by using an IFRAME. If they want to embed an icon or other image, they simply need to insert the HTML IMG tag reference in their format handler, and setup a callback to handle it when GtkHTML requests it. EMFormat has some helper classes to make this only a few lines of code, including generation of the IMG SRC URL. IFRAMEs work identically to IMG tags, and similar process is involved with embedding custom widgets using the OBJECT tag. EMFormatHTML takes care of calling the right callbacks for the right embedded reference from the right thread.

Since format handlers are chained off a given type, then a plugin can also inherit formatting behaviour as well as override it. This gives much greater flexibility since the plugin need only implement its behaviour in specific situations. e.g. an OpenPGP message handler could fall-back to the normal text-formatter if it doesn't detect the ASCII armour in a text/plain part. Or another handler may disable itself based on configuration or state.

All format handlers for all types must also be fully re-entrant code (more or less write-once global and static variables) if they call any other formatting functions.