
open, multi-language,
cross-platform MAPI implementation
Last Update: 25.06.2009
DocumentationAbout openmapi.orgOpenMapi.org provides a cross-language, multi-platform implementation of the MAPI API. |
Developer's HandbookIntroductionMAPI (Messaging Application Programming Interface) is an API for messaging commonly used by Windows and Outlook to talk to groupware servers like the Microsoft Exchange Server. Groupware servers are usually used to provide centralized storage, sychronization and transmission of mail, calendars, tasks and address books. All of these different applications share a common set of problems, particularly how to get the objects (like a mail, a calendar item) from the server to the client and how to keep all connected clients up-to-date, when data changes. MAPI provides an interface that can work with any of these objects using the same API and also is extensible, so new types of objects may be created and new properties may be added to existing objects like an email object. MAPI also hides from the client how the server stores the data or how it is sent over the network and while the Microsoft Exchange® Server is commonplace in many organizations other compatible servers like teamXchange or Zarafa are available. OpenMapi.org takes this concept a little further by providing a modern implementation that is language independant (Classic MAPI is built on COM and can only be fully used from C++.) and works on many platforms like Windows, Linux and Mac. We have also cleaned-up the API so it feels more like a Java or C# API. The MAPI ArchitectureOverviewMapi is fundamentally based on a client-server-model. The client will request some data from the server and display or modify it. The server is responsible for storing the data and for sending notifications to any connected client, informing it that data has been changed. In OpenMapi data is stored in objects. These objects do not really have a type. Objects have properties any object may have any arbitrary set of properties. There is a "type" property, that indicates that the object is used in a certain way (like a "Task" and that a common set of properties can be expected, but this is only a convention. Properties have a name (like Property.Body) and an associated type (like a string or an integer). As said, properties are set on an object and objects are collected in containers. ComponentsIn classic MAPI you only have a server (like Exchange®) and a client-side MAPI that plugs into the MAPI-COM-model and talks to that server from C++. A client (like Outlook®) will use the API to talk to the server. As a developer you get passed a pointer to the provider (which implements the MAPI-interface) by the MAPI subsystem. OpenMapi has a more complex set of components: The exact use depends on your choice of language and, to some degree, also on your operating system. Usually your OpenMapi.org library will provide an interface and a set of classes implementing it. In the case of JMapi there is only one "backend" for the interface and this backend will make calls to the OpenMapi.org Proxy server. The Proxy then calls any backend supported by NMapi. More information about how to run the Proxy server is available in the Administration Guide. If you use NMapi, then you can also call any backend directly (provided it is installed and distributed to your users.). In that case you will only have to deal with NMapi.dll and backend, for example a MailDir-directory or a teamXchange server. Message Store ProvidersAddressbook ProvidersMapi ObjectsIn classic Mapi, "Mapi Objects" are COM objects that implement some Mapi-Interfaces. One of the most basic of these interfaces is IMapiProp, implemented by any object that can have properties associated with it. There are other interfaces like IMapiContainer (which derives from IMapiProp) with other features that may be implemented as well. In OpenMapi a "Mapi Object" is represented by an object in your programming language. The exact type depends on the underlying Backend. You will access these objects through an interface like IMapiContainer (which is a normal C#/Java/etc. interface).
Mapi PropertiesAs said Mapi-Objects expose their data as properties if the object implements the IMapiProp interface. The IMapiProp interfaces provides methods to get/set properties or to find which properties are currently set on an object. Specifically the following operations are supported:
Unlike what you may be used to from your programming language, Mapi objects may contain any property. there is no concept of a "type" that defines which properties are available. There can, however, be a message class associated with an object - it's just another property really, a string, that defines which properties should be supported or can be expected by clients. There are some terms used with Mapi-Properties that often seem confusing, so I will define them first.
To retrieve a property you will pass its property tag (a 32-bit integer) to a method of IMapiProp. OpenMapi.org provides a list of predefined properties. For example the constant Property.Subject identifies a string that represents the subject of the current item (which can be a mail, task or calendar item or any other object). Custom properties (usually these are "named properties", see below) may be defined by clients to store arbitrary data. Transmitted properties & Messages classesWhile objects don't have types, they usually have a class. The idea is that messages of the same class should share the same properties. That means that a client should expect some properties on these objects and be able to set them. For example a mail client should be able to read and write the Property.Subject tag. If it deals with a mail-message it will probably try to read this property. Other properties are shared by most objects. For example (almost) any object will have an Property.EntryId which uniquely identifies the object in a message store. Property IDs from 0x6800 to 0x7FFF are reserved for properties that belong to a certain class. TODO! Additonally properties in some classes are not transmitted when sent to an external system. TODO! The Standard Mapi PropertiesTODO The EntryId-PropertyNamed Mapi PropertiesSnapshot and Multiview ObjectsMapi ContainersMapi TablesEvent Model & Mapi NotificationsNMapiProvider ConfigurationConnecting to a backend ...Backends are created by factiories. For example you can use the TeamXChangeMapiFactory to work with the teamXchange backend or the MaildirMapiFactory if you want to "connect" to a local mail directory. The backend can either be selected directly in the Code or - better - through a .NET configuration file. In order to do that, simply create a new instance of AutoConfigurationFactory as shown below: using NMapi; using NMapi.Flags; class Test { public static void Main (string[] args) { var factory = new AutoConfigurationFactory (); using (IMapiSession session = factory.CreateMapiSession ()) { session.Logon ("host", "user", "password"); } } } Then put the following code in you App.exe.config file (if you application is called App.exe): <configuration> <configSections> <sectionGroup name="nmapi"> <section name="core" type="NMapi.NMapiCoreSection,NMapi" allowLocation="true" allowDefinition="Everywhere" /> </sectionGroup> </configSections> <nmapi> <core backend="NMapi.Provider.Indigo.IndigoMapiFactory,NMapi.Provider.Indigo"> </core> </nmapi> </configuration> Here we have selected the Indigo-Backend, which is the backend used to talk forward data to the OpenMapi.org Proxy Server. Core APIIMapiProp - Getting PropertiesIMapiProp - Setting & Saving PropertiesIMapiProp - Deleting & Copying Properties/ObjectsIMapiContainer -IMessage -IMessageStore -IMapiTable & IMapiTableReader -
Events -Smart C# objectsLINQ APIData Binding for LINQ QueriesAdvanced: Custom ProvidersAdvanced: Proxy modulesThe OpenMapi.org Proxy Server can be extended with custom modules. Most of the proxy features like logging, load-balancing, etc. are implemented as modules as well. Writing a custom module is easy. Simply define a class that implements the IServerModule interface. This class can register for any RPC call by adding a '"PreCall" or "PostCall" attribute to a method. The method also needs to take the same parameters with the difference that they have to be passed using "ref" (making it possible to easily modify the incoming data.). The server will currently reflect on it's own assembly at runtime to find modules, so you have to put the file in the server directory and recompile the server. We will add support for modules in different assemblies later. public class MyModule : IServerModule { public string Name { get { return "NMapi Server MyModule"; } } public string ShortName { get { return "MyModule"; } } public Version Version { get { return new Version (0, 1); } } [PreCall (RemoteCall.OpenSession)] public void ProcessOpenSessionCall (ref string blah) { Console.WriteLine ("Hello Session from MyModule!"); } } You can also register a method to be called for any RPC request: [PreCall] public void CatchAllCall (RemoteCall call, object o) { // your code here } To see which calls you can intercept, take a look at the List of RPC calls. JMapiCreditsAuthor: Johannes Roith
|


