6.0.0-alpha14
6/24/25
Last Modified 11/23/16 by Michael Rubinsky
Table of Contents

ActiveSync Library Technical Information

This page is designed to give anyone working on the ActiveSync library in Horde 5.x a general overview of logic flow and what happens where and when.

General Library Structure

The logic for handling ActiveSync requests is split between 3 different libraries currently - Horde_Rpc, Horde_Core, and obviously Horde_ActiveSync. Horde_Rpc only handles the initial request and basically just passes on control to Horde_ActiveSync so this page will focus only on the other two libraries.

Horde_ActiveSync

This library contains the main logic for decoding WBXML from EAS requests, passing the request to the appropriate controller and then sending properly encoded responses back to the client.

TODO general description of the classes

Horde_Core

Core contains any code specific to handling Horde Groupware collections. This is where requests for information and changes to information are actually handled.

Factories

Horde_Core_Factory_ActiveSyncServer
Creates the main Horde_ActiveSync object. Injects the Horde_Core_ActiveSync_Driver, the WBXML encoder/decoder objects, the Horde_ActiveSync_State_[Sql|Mongo] storage object and the Horde_Controller_Request object.
Horde_Core_Factory_ActiveSyncState
Creates the state storage handler. The name is misleading (and will change in Horde 6) as this class has evolved to be more of a general storage handler and now handles more than just device state. We will assume a Sql storage backend for this document.
Horde_Core_Factory_ActiveSyncBackend
Creates the Horde_Core_ActiveSync_Driver backend driver. Injects Horde_Core_ActiveSync_Connector, Horde_ActiveSync_Imap_Adapter (if needed), the state storage driver, and the Horde_Core_ActiveSync_Auth object.

TODO ....

Protocol Overview

It's beyond the scope to explain the ActiveSync protocol in detail. For that, there is the official documentation. The most useful of these are
MS-ASCMD
Details every command/request and it's schema.
MS-ASHTTP
Documents the requirements and flow of the HTTP protocol as used in the EAS protocol.

There are also the individual documents for each collection type, such as MS-ASEMAIL, MS-ASTASKS etc... These documents are the best place to start when trying to track down issues such as "Protocol Error" issues with certain clients.

Logic Flow

I have a long-standing item on my todo list to generate an activity diagram for the program flow of an EAS request, but in the meantime here is a description of what happens.

EAS requests hit rpc.php first. There are a number of ways that these are differentiated from other RPC requests, but the main give-away is the REQUEST_URI containing Microsoft-Server-ActiveSync. A few things happen here before continuing. First, EAS requests are session-less, meaning that the entire Horde environment needs to be setup for each request. This is handled by explicitly setting $session_control = 'None' to force the use of the Null session driver in Horde. From there, we perform the same logic and checks like every other Horde RPC request. This includes having to initialize the Horde environment with NO authentication.

From here, we instantiate a Horde_Rpc_ActiveSync object and inject a Horde_ActiveSync object (which is created using Horde_Core_Factory_ActiveSyncServer).

Here, we perform some sanity checking on the request and sniff out what type of request we are handling. OPTIONS and Autodiscover requests are handled a little differently, but for now we will concentrate on the "normal" request handling.

The client must send certain data with each request. This data is either present as "normal" GET variables or is sent as BASE64 encoded binary data sent in QUERY_STRING (see Horde_ActiveSync::getGetVars()). The format of this binary data is beyond the scope of this page, but the data is decoded in Horde_ActiveSync_Utils::decodeBase64().

Cmd
This is the command or request type. E.g., SYNC, PING, FOLDESYNC
DeviceId
This is a unique identifier for the client. This value is only unique to the client, not to the account. I.e., the same physical device/application will have the same DeviceId. Multiple users can be associated with the same DeviceId.

Flow is turned over to Horde_ActiveSync::handleRequest(). This is where the interesting stuff starts to happen.

Life Cycle of a Client.

What we will describe is the life cycle of a client-server pairing from the initial connection to be able to synchronize changes. Let's start with a fresh, never before connected client. The first thing that happens is the OPTIONS request. This essentially tells the server what protocol versions the client supports and the server responds with (among other things) the version that it will be using.