The SyncML specification may be of help, but it's quite hard to read and obviously biased towards SyncML.
I've had to implement this for Task Coach, so here are a few ideas:
A modification flag is enough, a timestamp doesn't really provide much more information. Typically, my objects are in one of these states:
- None
- New
- Deleted
- Modified
The following transitions happen when the object is modified:
- None -> Modified
- New -> New
- Deleted -> (should not happen)
- Modified -> Modified
and the following ones when it is deleted:
- None -> Deleted
- New -> Actually deleted (it may be removed from storage)
- Deleted -> (should not happen)
- Modified -> Deleted
When synchronizing, the device first sends to the desktop all objects with a status different than None. The desktop asks the user to resolve conflicts if one of these has a status != None on its side. In any case, the object goes into state None on the device, or is deleted from storage if its state was Deleted.
Then, the desktop sends its own changes to the device. There are no conflicts possible since all objects are in state None on the device. Objects on the desktop go into state None or are deleted from storage as well, and sync is over.
There are two types of possible conflicts, depending on the device/desktop states:
- modified/deleted. If the user chooses to trust the device, the desktop object is replaced with the device one; else, the desktop does nothing and keeps the deleted state, so that the object will be removed from the device in phase 2.
- deleted/modified: If the device wins, the object is actually deleted from the desktop. Else, the object goes into state New on the desktop so that it is restored on the device in phase 2.
- deleted/deleted: Duh. Just remove it from storage.
- modified/modified: The user decides which values to keep, maybe on a field by field basis. The state stays to Modified on the desktop so that these choices are propagated back to the device in phase 2.
Some conflicts may be avoided if the Modified state is kept for each field, so that for instance an object with a modified Subject on the device and modified Summary on the desktop will not trigger a conflict.
You may take a look at the code for Task Coach for an example (SVN repository on SourceForge, it has both the desktop app in Python and the iPhone app). Actually, in this case I decided to use a simpler approach; I don't keep track of the state on the desktop. After phase 1 (device to desktop), I just make a full replacement of objects on the device with the ones on the desktop. Thus, there are no conflicts (the device always wins).
Obviously, this only works between two fixed devices; if you want to synchronize with several phones/desktop apps, you have to assign a unique ID to each and keep different states for different devices/apps. This may begin to get hairy.
HTH