[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