MAPIStore 1.0 backend.folder structure

folder.open_folder

This function opens a folder in the backend. It should only perform an action when the folder is not a root/mapistore folder (referenced in openchange.ldb), since these specific root folders are opened during context creation and morphed/returned as a folder object when context.get_root_folder returns.

For any folders within a backend and different from the root folder, the folder should be opened. The function takes in parameter:
  • void *parent_folder: the parent folder object of the folder to open
  • TALLOC_CTX *: the memory context to allocate folder_object with
  • uint64_t fid: the folder identifier of the folder to open
  • void **folder_object: the opened folder object to return

Folders are opened within a given context, which folder object is retrieved through context.get_root_folder call. While this specifically apply to folder underneath the root folder, the same logic apply to sub folders which parent is not the root folder object within the context. It requires either to keep a reference to the root folder along newly created folder objects or be able to walk through the associated MAPIStore URI and figure out what the root folder URI is.

folder.create_folder

This function only creates a folder within a existing context. The resulting created folder will have a URI using the same backend that the context it is using. Upon success, the folder is opened and returned within the void ** parameter. The function takes in parameter:
  • void *parent_folder: the parent folder object of the folder to be created
  • TALLOC_CTX *: the memory context to use to allocate the new folder upon success
  • uint64_t fid: the folder identifier for this folder
  • struct SRow *aRow: an Exchange data structures which must store PR_DISPLAY_NAME or PR_DISPLAY_NAME_UNICODE (the folder name to be created)
  • _void **childfolder: the folder object for the newly created folder
The SRow structure may also supply the following Exchange properties:
  • PR_COMMENT or PR_COMMENT_UNICODE: the folder description
  • PR_PARENT_FID: the folder identifier of the parent folder object
  • PR_CHANGE_NUM: the new change number

folder.delete_folder

folder.open_message

This function opens a message and returns a message object. This function takes in parameters:
  • void *folder_object: the parent folder object of the message to open
  • TALLOC_CTX *: the memory context to use to allocate the message to be opened
  • uint64_t mid: the message identifier of the message to open
  • void **message_object: the message object to return

folder.create_message

This function creates a temporary message object. Messages are a bit particular in Exchange, because they are not created through a single transaction. Creating message is the first operation of the process, but message doesn't get available/saved or sent until you respectively call save or submit backend methods. Between create and save/submit, MAPI clients can perform several operations such as:
  • set or delete properties
  • add or delete attachments
  • add or delete recipients

Until save/submit is called, this message object remains virtual. However MAPI clients need a way to reference this object within current context until it's saved. This is why OpenChange generates a MID (message identifier) and requests the backend to temporarily create an associated MAPIStore URI. But this MID/MAPIStore URI couple is not stored within the user idexing.tdb database.

Remember that mapistore calls backend with MID/FID and expect the backend to lookup associated mapistore URI.

It is the backend's responsibility to virtual store this message until save/submit is called. If no such mechanism/API exist in your backend or if you want to speed up the process, you can use the ocpf (http://apidocs.openchange.org/libocpf/index.html) library which will store everything for you properly.

The function takes in parameter:
  • void *parent_folder: the parent folder object in which the message has to be created
  • TALLOC_CTX *: the memory context to use to create the message object
  • uint64_t mid: the message identifier for this new message
  • uint8_t associated: whether this message is already associated to a file or not (see below)
  • void **message_object: the message object to return

Regarding the associated parameter, it is a flag that tells the backend if it already has an associated file for this message or not. Some background is required to understand this concept:

When you create a message, you will set properties for the message and finally save it. However, you may not have a 1 to 1 mapping between MAPI properties and what the remote system supports. Many properties are Exchange specific and your remote system may not have associated parameters for them.

Here is the crucial part: there is a small amount of information that a remote system is unlikely to map/support but which ARE REQUIRED for the message or folder to be valid/fetched properly by MAPI clients.

While you can skip/drop many Exchange properties, you CAN'T skip/drop the required ones.

The associated parameter lets your backend know if it already has a file or structure associated to this message in which it stores exchange properties it can't map.

folder.delete_message

the delete_message operation deletes a message given its message identifier within a given folder. This function takes in parameter:
  • void *folder-object: the folder object in which the message to delete is stored
  • uint64_t mid: the message identifier representing the message to delete
  • uint8_t flags: flags that indicate the kind of deletion

Possible deletion flags are:
- MAPISTORE_SOFT_DELETE: to virtually delete the message. The message is not physically deleted on the remote system, it is just marked as SOFT_DELETED in the indexing database of the user. It can be recovered at any time.

folder.move_copy_messages

folder.get_deleted_fmids

folder.get_child_count

This function retrieves either the number of messages, FAI messages or folders within specified folder. The function takes in parameters:
  • void *folder_object: the folder on which the count has to be retrieved
  • uint8_t table_type: the type of item to retrieve. Possible values are listed below
  • uint32_t *rowCount: the number of elements retrieved

Possible values for table_type are:
- MAPISTORE_MESSAGE_TABLE: the number of messages within the folder
- MAPISTORE_FAI_TABLE: the number of FAI messages within the folder
- MAPISTORE_FOLDER_TABLE: the number of folders within the folder

folder.open_table

This function creates a table object to be used along with backend's table operations. The function takes in parameter:
- void *folder_object: the folder on which the table has to be created
- TALLOC_CTX *: the memory context to use to create the table
- uint8_t table_type: the table type to create. See below for possible table_type values
- uint32_t handle_id: Exchange temporary id for the object. Used for the moment for notifications on table
- void **table_object: the table object to return
- uint32_t *row_count: the number of row of the table to be returned. It is used by OpenChange server and returned clients, so they know how many rows are available and how much they can query.

Possible values for table_type are:
- MAPISTORE_MESSAGE_TABLE: creates a table which only lists messages
- MAPISTORE_FAI_TABLE: creates a table which only lists FAI messages
- MAPISTORE_FOLDER_TABLE: creates a table which only lists folders
- MAPISTORE_PERMISSION_TABLE: creates a table which list permissions for the folder

For the handle_id, it is a hackish implementation from SOGo. It is used to process notifications on tables when registered by clients. This number is associated with the table objects and the couple is used to find a table and trigger a notification payload upon table changes.

The handling of handle_id can be avoided for now as it is likely to change with OCSManager final implementation.

OpenChange is waiting for a table_object (void **) which it doesn't care about, but will pass it to your backend when a new table operation occurs. It is also waiting for the number of rows in the table (uint32_t *row_count)

Also available in: HTML TXT