[sync] SyncML working, part 4/3

Karsten Fourmont fourmont at gmx.de
Wed Jun 30 10:23:41 PDT 2004


In the good tradition of extending trilogies beyond there original meaning:

I realized that neither zips nor tgz seem to be cherished on this 
mailing list. So instead of the tarball here's the link.

http://www.fourmont.com/zombie/SyncML_complete.tgz (20kb)

The docs I mentioned are attached as text.

Next time, it will be Mostly Harmless
   Karsten




-------------- next part --------------


How to get SyncML working with your P800/P900:
[[somebody with access to other phones might add instructions
for these as well. Thanks]]

Start "Remote Synchronisation" from you phones app launcher:


1)Select edit/settings and put in the following:

"Server" tab:
server address: http://yourserver.com/horde/rpc.php
user name: your horde user name
password: your horde user password

"Protocol" tab:
Needs not to be filled in. Unless you have your web-server
configured to require HTTP Authentification.


2) Configure sync types:

Start with Calendar/Tasks:

	check "activate"
	name can be anything
	server database: must be "calendar"

For Jotter the server database name is "notes". 

However you should start with activating one type only.

3) Hit Sync, wait and hope.

Now Synchronoisation should take place. During the first sync
a set union of the client's and server's data sets are created.
Further Sync runs should only transfer the changes since last
time.


If it's not working:

make sure the /tmp/sync directory exists and is writeable by your
webserver (user might be wwwrun). Try to Sync once more and check
the input/output in this directory. 
Maybe change your php.ini settings so php logs ERROR messages and
NOTICEs in a file as well. Check this file. Your phone gets 
confused when the XML is cluttered with stuff like

"PHP Notice:  Undefined index:  body in /blah/blub.php on line 256"

Consult sync at lists.horde.org and the syncml.org protocol specification.

-------------- next part --------------


rpc.php in horde's main directory is the starting point for our (and any) 
RPC call.

It determines the $serverType ("syncml" for us) and then does something 
like this:

$server = &Horde_RPC::singleton($serverType); // [will include RPC/syncml.php and create the class therein]
$server->authorize();
$input = $server->getInput(); // [basically the HTTP POST data]
$out = $server->getResponse($input, $params);
echo $out

So the main part takes place in getResponse of 
framework/RPC/RPC/syncml.php's Horde_RPC_syncml class and there in 
getResponse:


First, XML_WBXML_ContentHandler is installed as an output content handler:

$this->_output = &new XML_WBXML_ContentHandler();

Despite the name, this class has (almost) nothing to do with WBXML.
It's a helper to produce xml. To do this, it has 4 main methods:

1) startElement($uri, $element, $attrs) produces an <$element xlmns=$uri 
   attr1=v1 ...> opening tag
2) characters($str) addes $str to the content
3) endElement($uri, $element) produces a closing tag </$element> 
and finally
4) getOutput() returns the output produced so far

All subsequent code produces output by calling functions 1)-3)

After installing the output content handler, Horde_RPC_syncml::getResponse 
continues with

$this->_parse($request); 

do do the actual parsing and output creation and then finally

$xmlinput = $this->_output->getOutput();

to retrieve the created output from the content handler. 
The name $xmlinput is misleading, it should be called xmloutput instead.

So our quest for the code continues withing the Horde_RPC_syncml's _parse 
function:

It creates an XML Parser and registers the class (well, the object) itself 
as  element handlers: 
_startElement,_endElement, and _characters, which only format the data a 
bit and call startElement,endElement, and characters  respectively.

Please note, that start/endElment sounding functions are used for processing
the input as well as for creation of the output. 
This can be somewhat confusing. As a rule of thumb, code that produces xml 
output contains reference to an output  var and looks like this:

$this->_output->startElement(...);

After the XML parser is istalled, it is fired and the execution takes place 
in the element handler functions.

A syncml message (input as well as output) has this structure:
<SyncML>
  <SyncHdr>
    ...stuff...
  </SyncHdr>
  <SyncBody>
    ...stuff...
  </SyncBody>
<SyncML>

the content handler in Horde_RPC_syncml delegate the work for header and 
body to the two sub-content handlers Horde_SyncML_SyncMLHdr and 
Horde_SyncML_SyncMLBody which reside in framework/SyncML/SyncML.php. 
So at least we made it to the to the SyncML package by now...

The job of Horde_SyncML_SyncMLHdr is to read all the values in the header 
and store them in a php session (custom session, not normal horde session 
system) of type Horde_SyncML_State. After all header data is collected, 
outputSyncHdr write a SyncHdr as output.

Horde_SyncML_SyncMLBody is another delegator. First it creates a 
Horde_SyncML_Command_Status to output the status-code of the session 
(authorized or not).
The content of the <syncBody> element are command(-tags): for each element 
in there, an appropriate handler is created with
Horde_SyncML_Command::factory($element);
and assigned the tasks of handling this command. 
So execution continues with classes in Horde/SyncML/Command/ which are
all children of  Horde_SyncML_Command. 

>From here, you're on your own. Just two more facts:

1)
processing of changes received from the client are handled in
SyncML/Sync.php (not to be confused with SyncML/Command/Sync.php) and
there in runSyncCommand($command) command is one of 
Horde_SyncML_Command_Sync_(Add|Delete|Replace)

2)
The other way around:
creating changes on the server for the client is done after the changes
from the client have been processed. This is done in TwoWaySync.php.
Some care has to be taken to avoid that the changes that are received 
from the client are considered "new changes" and echoed back to the
client. That would result in severe data duplication meltdown.


-------------- next part --------------


SyncML Primer:
--------------

A SyncML Protocol Primer

The specification can be downloaded from www.syncml.org.
This Primer deals with SyncML 1.0.1 only.

Basically a SynML Synchronisations consists of 6 steps:
Three packages sent from the Client to the Server and three
packages the other way round.

Here's a brief description of these 2*3 steps. The Chapter 
references refer to XML examples for these steps in 
SyncML Sync Protocol, version 1.0.1(pdf) from syncml.org.
I found these examples most helpful.

Here we go:

1a) Sync Initialization Package from Client (Chapter 4.1.1)

Client starts communication, sends authentification and device 
info and maybe info about previous sync if any.

1b) Sync Initialization Package from Server (chapter 4.2.1)

Server responds with session info if authorisation was successfull, provides 
device info if requested and the synchronisation type (like TwoWaySync or 
SlowSync) that is suitable for this run. Basically, if both sides "remember" 
the same timestamp for the previous sync run, a TwoWaySync can be used to 
transfer only the differences since then. Otherwise or for initial sync, 
a SlowSync is used. In that the client sends all its data to the server 
which then handles them.

2a) Client Sending Modifications to Server (Chapter 5.1.1)

The client sends all its modifications since the last sync run 
(or all data for SlowSync) to the server

2b) Server Sending Modifications to Client

The server incoporates the changes from the client and now sends its 
modifications to the client.

3a) Data Update Status to Server (Chapter 5.3.1)

A key concept of SyncML is that client and server have their own internal 
representation of the data and user different primary keys. To identify 
items there has to be a mapping between the client's keys and the server's 
keys. (primary keys are relative URIs in SyncML language). 
This map is maintained by the server. After the client has incoporated the 
servers data in its own database it sends its new primary keys 
(<source><LocURI>) for the changed data back to the server. 
The server can then update its map.

3b) Map Acknowledgement from Server (Chapter 5.4.1)

Basically says: "Whoppie, we're through. See you next time".


XML Specification:


Each SyncML Packet consists of one SyncMLHdr Element an one SyncMLBody Element.

The header contains authorisation and session information.
A typical header sent from the server might look like this:

<SyncHdr>
  <VerDTD>1.0</VerDTD>
  <VerProto>SyncML/1.0</VerProto>
  <SessionID>424242424242</SessionID>
  <MsgID>2</MsgID>
  <Target>
   <LocURI>111111-00-222222-4</LocURI>
  </Target>
  <Source>
    <LocURI>http://mysyncmlserver.com/horde/rpc.php</LocURI>
  </Source>
  <RespURI>http://mysyncmlserver.com/horde/rpc.php</RespURI>
</SyncHdr>

The SyncBody contains the following elements (called "commands") as specified in the DTD:

(Alert | Atomic | Copy | Exec | Get | Map | Put | Results | Search | Sequence | Status | Sync)+, Final?

CmdID: each command in a packet has a unique command id like <CmdID>1</CmdId>

We discuss only Alert,Get,Put,Results,Map,Status Sync and Final here.


Get

The Get request command works similar to HTTP GET: it is intended to request data from the communication partner.
Currently its only use is to retrieve "./devinf10" (or 11 for syncml 1.1) which contains information about the sync capapilitys of the partner.

Put

Put is similar to HTTP POST: it's designed to transfer data to the communication partner. As with get, the only use at the moment is to publish the ".devinf10" device information to the communication partner. A typcial first packet from the client would include a GET for the servers devinf and a put with the client's own devinf data.

Result

The Result Element is used to respond to a GET Command and contains the requested data, i.e. the devinf data.

Status

In General, for each command there must be a status response from the other side. (For exception see the spec.)

The Status includes a CmdID (like any command)
It has a MsgRef and CmdRef to identify the command it responds to: MsgRef identifies the packet (given in the Header) and
CmdRef the CmdId of the original command. There's also a <cmd> Element to specify the type

<Status>
  <CmdID>3</CmdID>
  <MsgRef>1</MsgRef>
  <CmdRef>2</CmdRef>
  <Cmd>Put</Cmd>
  <SourceRef>./devinf10</SourceRef>
  <Data>200</Data> <!--Statuscode for OK-->
</Status>

Sync

Alert

Sync and Alert is where the action takes place. Unfortunately the primer is not yet finished.
Stay tuned or check the Spec yourself... 






More information about the sync mailing list