On Wed, 2011-10-12 at 12:25 +0200, Patrick Ohly wrote:
For those who don't know, Srini wrote an Evolution plugin which
automatically configures ActiveSync for email and contacts/calendar. The
latter is based on SyncEvolution.
Right now he is using the SyncEvolution command line. The intention is
to use the D-Bus API instead, because that will allow better control
over error cases and enables more advanced features (controlling
syncing, for example).
Here's the sequence of steps for configuring SyncEvolution for
ActiveSync when using the command line:
1. configure ActiveSync daemon in gconf, using some kind of
<eas_account_id> - email address is common, but not required
2. configure access to server:
syncevolution --configure \
target-config@exchange addressbook calendar todo memo
Note 1: the "target-config@exchange" target config must not exist yet,
because otherwise it will be overwritten without warning.
Note 2: the <eas_account_id> cannot be shared between different configs
because it is tied to the state of one account in the ActiveSync server
(sync keys), in contrast to a CalDAV target config, which is stateless.
For the same reason, item operations on that target-config will interfere
with syncing with it (force a slow sync).
A GUI tool either has to check all existing target configs for a collision (hard)
or we impose additional policies for ActiveSync configs. I propose:
- simplify <eas_account_id> such that it consists of characters a-z, 0-9 and
hyphen by lowercasing all characters and replacing other characters with
a hyphen (Patrick.Ohly(a)foo.bar => patrick-ohly-foo-bar)
- use that <simple_eas_account_id> instead of "exchange"
Note 3: the command above uses the default databases. It is possible to
get folder IDs from the activesync daemon and set those with
Note 4: todo and memo are configured above although not supported yet.
Note 5: peerType is a hint for UIs that tells them what the other properties
in the config really mean. For example, in this case setting the password
in the config has no effect and must be done elsewhere. This wasn't (and
still isn't) in the original ActiveSync backend README.
I will provide an ActiveSync config template similar to the WebDAV context;
then setting syncURL, peerType and backend properties above can be replaced
with "--template ActiveSync".
3. configure syncing:
syncevolution --configure \
--template SyncEvolution_Client \
Note 1: because only calendar and addressbook really work, only
those are enabled here.
Note 2: the default local backends and databases are used. To lock this
down, use <source>/backend=evolution-contacts/events/tasks/memos for Evolution
and <source>/database=<evolution ID> (for example, local:system or
local:1237386992.13712.0@pohly-MOBL) - warning, I think these IDs are subject
to change in Evolution 3.4. Probably the user will have to fix configs manually,
because I'm not aware of migration support by EDS itself.
Note 3: syncing will not run unless autoSync=1 is set to enable polling.
Srini, how much of this do you have working already? Have you seen a
sync of contacts and calendar running? Do you support removing configs?
Currently calendar/contact syncing is configured automatically and its
removed when the evolution account is deleted. I don't initiate syncing
though, as there is no proper interface from evolution on how we can
initiate this. I had some crashes on the addressbook and calendar sync
was fine when I tried.
Translating this into D-Bus API calls makes the process a bit harder.
One of the obstacles is that a config has to be locked first before
modifying it by obtaining a session. This prevents race conditions
between different clients (less likely) and client and sync daemon (more
likely, in particular with auto syncing enabled). I considered whether
write access should be allowed without that locking, but decided against
it. The consequences are simply too hard to predict. Think removing a
config and its associated databases while a sync using it runs.
Evolution currently uses account settings that can be modified in gconf
at any time, but work is under way to put them into plain files under
the control of a D-Bus service - that's exactly how SyncEvolution always
has worked. SyncEvolution going in the other direction (and thus
suffering from the problems the Evolution devs are currently solving)
just doesn't make sense.
Obtaining a session for config changes is done in three steps
1. session = Server.StartSessionWithFlags(<config name>,
2. listen to session.StatusChanged()
3. check session.GetStatus(): if 'idle', it is ready for use; if
still 'queueing' (yes, typo is part of the API - sorry), wait
for StatusChanged('idle') and
Typically a session will be usable right away on an idle
syncevo-dbus-server. If a sync runs, the sync has to complete first,
which should somehow be indicated to the user.
Note that the session is limited to making changes to <config name>.
That is not entirely enforced because all configs use some shared
properties that also appear in other configs. That's not a problem,
because currently no concurrent sessions are supported.
But it makes the ActiveSync configuration awkward, because two sessions
will be needed, one for the target config and one for the sync config,
which requires additional code in the D-Bus client and leads to
additional error states (what if the target-config could be created, but
not the sync config?).
Therefore I suggest to accept that sessions for config changes always
lock the whole config tree, which allows that any config can be changed
in such a session. This is an extension of the current D-Bus API and
thus backwards compatible:
* Session.SetConfig() modifies the config named in StartSession,
* a new Session.SetNamedConfig(<config name>) modifies any config;
it is only allowed in a session which was started with
Server.StartSessionWithFlags(<config name>, ['no-sync']), where
<config name> may be empty - such a session will prevent any
other session from running, while normal sessions may one day
run concurrently (not supported at the moment)
* there is no need for a Session.GetNamedConfig() because
Server.GetConfig() already provides that - should it be added
anyway, for the sake of completeness?
With this revised API and taking into account the policy outlined before
configuring ActiveSync via D-Bus becomes:
A. session = Server.StartSessionWithFlags('', ['no-sync'])
B. listen to session.StatusChanged()
C. wait for session to become 'idle' (GetStatus() or signal)
D. target_config = Server.GetConfig('ActiveSync@<simple_eas_account_id>',
E. target_config['']['username'] = <eas_account_id>
update=False, temporary=False, target_config)
G. sync_config = Server.GetConfig('SyncEvolution_Client', template=True)
H. unset sync_config['']['username'/'password'], if set
I. sync_config['']['ConsumerReady'] =
target_config['']['ConsumerReady'] (might not be set)
J. sync_config['']['PeerName'] = some user visible name for the sync
config; if nothing
better is available, use <eas_account_id> because otherwise UIs will have to
to the config name, which would be the simplified string in this case
K. sync_config['']['autoSync'] = 1
L. modify sync_config['source/<source>']['sync'] according to the
user's choice for
enabling/disabling certain kinds of data, always disable 'memo' and
M. session.SetNamedConfig('<simple_eas_account_id>', update=False,
Note that this intentionally doesn't mention setting 'backend' on the
'calendar' or 'addressbook' source. That's because these settings
shared with other sync configs in the default context (chosen implicitly
in step M by not having an @<context> part in the config name). The idea
here was that advanced users can choose their default databases once
(via the command line, GTK sync-ui doesn't support it) and then
configuring further sync configs will automatically use those databases
(because GTK sync-ui will never change the 'backend' property).
It is possible to define the <simple_eas_account_id> sync config inside
its own context (for example,
<simple_eas_account_id>@<simple_eas_account_id>), which would give the
UI full control over the configuration of all sources.
But restoring local databases finds data dumps based on the source name
and its context name. Anything more fancy would suffer from loopholes
(is database="Personal Calendar" with backend=eds-contact in
default/addressbook the same as database=local:system with
backend="Evolution Contacts" in other-context/personal-contacts?). This
means that if multiple sync configs in diffrent contexts access the same
local database, the user has to be more careful about picking the latest
data dump - not at all obvious.
I think I rather prefer a UI design where the user configures his local
database globally, or alternatively a design where each local database
always matches 1:1 with a peer.
I believe the Evolution plugin follows the later approach, and thus
should use <simple_eas_account_id>@<simple_eas_account_id>. Srini, is
Yes, for every account there is a corresponding calendar/contact created
under a new ESourceGroup named after the email id of the account.