===============================================================================
              The Design of Empath 
              Guide for developers 
-------------------------------------------------------------------------------
              Rik Hemsley rik@kde.org 
              Last update: Wed Mar 1 2000
===============================================================================
              Introduction 
-------------------------------------------------------------------------------

  The design of Empath may be a little confusing at first. Please
  take the time to read this document. It should help make things a little
  clearer. You should hopefully end up with the impression that the design
  is actually quite simple !

  ** NOTE The design is changing slightly to use threads. Because Empath
          was designed to do as much stuff async as possible, this does
          not have a huge impact on the general structure, but watch out !

===============================================================================
              Contents 
-------------------------------------------------------------------------------

  The Kernel
    Introduction
    URLs
    General Operations
      Asynchronous Operations
    Composing
    Filtering
      Introduction
      What is a filter ?
      Example
      Source URL
      Matcher
      Event Handler
    Sending Mail
    Kernel Summary
  The User Interface

===============================================================================
              The Kernel 
-------------------------------------------------------------------------------
Introduction
-------------------------------------------------------------------------------

  The kernel does most of the hard work. It is designed to be very open,
  in the sense that the parts are not tied tightly together with
  interdependencies.

  You can find all the kernel code in lib/.

  Note: Empath used to 'contain' a library called 'librmm'. This library
  does the message parsing necessary for Empath to manipulate IMM (Internet
  Mail Messages.) Recently this library has been separated from Empath
  proper and moved to its own 'module'. You should find a directory
  called 'rmm' on the KDE CVS server, in the same module where you found
  Empath. There is now a separate DESIGN document in the rmm subdirectory.

-------------------------------------------------------------------------------
URLs
-------------------------------------------------------------------------------

  The system works with URLs. For the moment, these are of proprietary format
  and look like:

  empath://<mailbox name>[/<folder path>][/<message id>] 

  So an URL which references a message with id 'some_long_message_id' in
  mailbox 'Local', folder 'Personal' and subfolder 'Charlie' would look like
  this:
  
  empath://Local/Personal/Charlie/some_long_message_id 

  Note that spaces are allowed in the URLs for the moment.

  You can see from the above that there's no reference to the type of
  the mailbox. Empath's kernel tries to hide the network. The only place
  you'll find networking code (and hence knowledge that a network exists)
  is in classes that need it, e.g. EmpathMailboxSendmail. Even the class
  EmpathMailboxPOP3 don't know about networks. It talks to the kio_pop3
  ioslave.

-------------------------------------------------------------------------------
General operations
-------------------------------------------------------------------------------

  From anywhere in Empath, you can reference a mailbox or a folder.

  This is done using the Empath object, of which there can be only one (tm).

  The macro 'empath' references the Empath object from anywhere within the
  system. Just include 'Empath.h' to get the macro defined. If you have an
  URL like this:

  empath://a mailbox/a folder/another folder/bigLongMessageID.localhost 

  You can get a pointer to the mailbox 'a mailbox' that's referenced in
  there like this:

  EmpathMailbox * m(empath->mailbox(url)); 

  Remember to check the pointer isn't 0.

  Note: The class 'Empath' implements the design pattern 'Facade'.

...............................................................................
Asynchronous Operations
...............................................................................

  To avoid stalling of the interface, Empath supports doing many operations in
  the background.

  If you're writing code for Empath and you want a message - say you want
  to save it to a file, you must:

  Ask Empath to retrieve the message and pass it a pointer to 'this' to
  be notified when the job is complete.

  empath->retrieve(EmpathURL("empath://Inbox/a_message_id"), this);

  You must provide the right slot to receive the signal.
  The slot names are in EmpathJobScheduler.cpp.
  In the future, I might allow passing SLOT(mySlotName(EmpathSomethingJob))
  to allow you to choose your own name for your slot.

  When Empath calls the slot you connected to jobComplete(), you
  can pick up data/info from the job.

  MyObject::s_retrieveJobComplete(EmpathRetrieveJob job) {
    RMM::RMessage m = job.message();
    // Check if message is ok using either:
    // if (job.success())
    // OR
    // if (!message.isNull())
  }

  Other operations are also asynchronous. For example, you can do:

  empath->remove(const EmpathURL &);

  If you don't care if the message is removed or not, simply don't pass
  'this' as the last parameter.

  Note: The 'Job' system in Empath is an implementation of the
  design pattern 'Command' (also known as 'Action' or 'Transaction'.)

-------------------------------------------------------------------------------
Composing
-------------------------------------------------------------------------------

  If the user wants to compose a message, you can just call
  empath->s_compose(). See also empath->reply(...) &c.

  The mechanism by which composition works is quite logical.

  EmpathComposer creates and looks after objects of the class
  EmpathComposeForm. It fills in any values it can in this form and then
  passes it back to Empath. This means that if you reply to a message,
  EmpathComposer will try to fill in a form addressed to the sender(s)
  of the message.

  When EmpathComposer has done its dirty work, it signals that the
  form is ready. Empath then re-fires that signal. EmpathUI will then
  notice the signal and create a composition window, passing along
  the composition form. This form is then used to fill in the various
  fields in the composition window.

-------------------------------------------------------------------------------
Filtering
...............................................................................
Introduction
...............................................................................

  All automatic operations are done by filters.

  When an EmpathMailbox notices that a new message is available, it doesn't do
  anything with it* It tells Empath that the message has arrived. Empath lets
  the filter mechanism know. The filter mechanism is basically a list of
  EmpathFilter.

  Note: The Empath filter system (specifically, the matching of messages
  performed by EmpathMatcher objects) implements the 'Chain of Responsibility'
  design pattern.

  * Actually, this is at the moment untrue. When Empath sees a new message
    in a maildir box (the only box currently supported,) it will simply
    notify anyone who cares that a new message has arrived. The filtering
    mechanism will be put in place shortly, once the core functionality
    is 100% solid.

...............................................................................
What is a filter ?
...............................................................................

  Each EmpathFilter consists of a source URL, 1..n EmpathMatcher and an
  EmpathFilterEventHandler.

  Example
  -------
  
  A mailbox signals that an event has occurred (new message). The filter
  mechanism goes through each filter in turn, and tells it that the new message
  has arrived. It gives the filter an URL.

  The filter compares the mailbox and folder parts of this URL with its own
  'source URL'. If they match, it knows that it should try to match this
  message. Basically the source URL just specifies the folder that the filter
  operates on. So, if the filter is set to look at messages from this
  mailbox/folder, it tells its matching mechanism to try to match the message.

...............................................................................
Matcher
...............................................................................

  A matcher may request information about the message referenced by
  the URL. Of course, it does this via calls to empath->message(),
  to get the message data. Note that Empath caches all messages, so
  multiple calls to empath->message() shouldn't result in multiple
  network transactions. If any of the matchers match the message, then the
  filter continues by running the EmpathFilterEventHandler.

...............................................................................
Event Handler
...............................................................................

  The handler may perform any action it likes. Currently these options have
  been set up, but it's trivial to add more: Move to folder, Copy to folder,
  Delete, Ignore, Forward. The handler may then request that no further filters
  run. Move to folder does this:

  // We have already requested the message and been told it's ready
  RMessage * m(empath->message(messageURL));

  EmpathFolder * f(empath->folder(destinationURL));

  if (f->writeMessage(m));
    empath->remove(messageURL);

  See how it works ? Get the message data, write it to the destination
  folder. If the write worked, remove the original message. Note that
  EmpathFolder::writeMessage() actually does this:

  EmpathMailbox * m = empath->mailbox(url);

  return (m != 0 && m->writeMessage(url, message));

-------------------------------------------------------------------------------
Sending Mail
-------------------------------------------------------------------------------

  If you want to send a message straight away, call:
  
  empath->send(RMessage &) 
  
  If you want to add a mail to the queue, call:
  
  empath->queue(RMessage &) 
  
  If you want to send all messages in the queue, call:
  
  empath->sendQueued() 

  Simple ? Quite !

  The Empath object keeps a pointer to an object of type EmpathMailSender.
  This pointer is updated if the user switches the type of sender they
  wish to use.

  Empath simply passes the message you give it along to EmpathMailSender.

  Operations specified in the base class (EmpathMailSender) perform
  queuing of the message if necessary, then call derived-class methods
  to perform the actual delivery.
  
-------------------------------------------------------------------------------
Kernel Summary
-------------------------------------------------------------------------------

  You should by now be able to see that as a user (writing 'user' code,)
  you don't have much work to do. If you want the data of a message, you
  simply ask for it. If you want to send a new message, you just ask.
  Empath handles the rest as intelligently as it can.

  The design is geared towards keeping the various components separate
  and, in the future, allowing adaptation for extensions such as scripting.

  Bindings for scripting are not currently planned, but keeping Empath's
  design open and dependency-free will continue to be a priority.

===============================================================================
              The User Interface 
-------------------------------------------------------------------------------

  The UI is itself split into modules. There are three kparts-based
  widgets in parts/.

  The rest of the UI, which includes utility widgets and shells for
  embedding the kparts-based widgets, is in ui/.

===============================================================================

