4 * Author: Beat Forster (bfo@synthesis.ch)
6 * C/C++ Programming interface between the
7 * Synthesis SyncML engine and
8 * the database layer for plug-ins
10 * Copyright (c) 2005-2009 by Synthesis AG (www.synthesis.ch)
15 * This is the calling interface between the Synthesis SyncML engine
16 * and a customized module "sync_dbapi".
17 * The same interface can be used either for Standard C or for C++.
18 * And there is a equivalent interface for JNI (Java Native Interface).
19 * Normally the customized module will be compiled as DLL and will
20 * be called by the SyncML engine. A linkable library is available
23 * For more detailed information about the DBApi interface
24 * please consult the SDK_manual.pdf which contains a tutorial,
25 * detailed descriptions and some example code.
27 * The flow for accessing the datastores is always the same:
28 * The SyncML engine will call these routines step by step
30 * DATASTORE ACCESS FLOW
31 * =====================
34 * 2) [ContextSupport] (optional)
35 * 3) [FilterSupport] (optional)
36 * 4) [Read Admin Data] (optional)
39 * 6) do ReadNextItem while (aStatus!=ReadNextItem_EOF);
40 * 7) any number of random calls to:
43 * - [AdaptItem] (optional)
47 * 10) any number of random calls to:
56 * - [AdaptItem] (optional)
57 * - FinalizeLocalID (at the end)
60 * 12) [Write Admin Data] (optional)
64 * NOTE: 'DisposeObj' calls can occur anywhere between any statement
65 * of the flow above (but not before 'CreateContext' and not after
66 * 'DeleteContext'). The SyncML engine is responsible for
67 * disposing all <aItemData> and <aItemID> objects after use.
69 * NOTE: Returned errors (value > 0) will influence the flow
70 * Error at 1) will not call any further step.
71 * " " 2)..3) these functions do not return errors
72 * " " 5)..10) will cause an 'EndDataWrite' call with
73 * <success> = false, then 'DeleteContext'.
75 * 11)..12) 'DeleteContext' will be called afterwards.
77 * The module must be able to handle several contexts in parallel.
78 * All routines will have an <aContext> parameter (assigned by
79 * 'CreateContext'), which allows to identify the correct context.
80 * Routines can be called from different threads, but they are
81 * always sequential for each context. If the thread changes,
82 * 'ThreadMayChangeNow' will notify the module about this issue.
83 * This routine can left empty and ignored, if not used.
85 * NOTE: As the SyncML engine calls the plug-in multithreaded,
86 * all global structure accesses must be thread save.
93 /* Global declarations */
94 #include "sync_dbapidef.h"
97 #if defined __cplusplus
98 /* combine the definitions of different namespaces */
100 using sysync::uInt32;
101 using sysync::CContext;
102 using sysync::CVersion;
103 using sysync::TSyError;
104 using sysync::ItemID;
106 using sysync::cItemID;
107 using sysync::cMapID;
108 using sysync::appCharP;
109 using sysync::cAppCharP;
110 using sysync::appPointer;
111 using sysync::memSize;
113 using sysync::SDK_Interface_Struct;
114 using sysync::DB_Callback;
115 using sysync::UI_Call_In;
119 /* C/C++ and DLL/library support
120 * SYSYNC_ENGINE : true ( within the engine itself ) / false ( outside )
121 * SYSYNC_ENGINE_TEST: true ( within a test engine module ) / false ( outside )
122 * DBAPI_LINKED : true ( at standalone APP, e.g. "helloX" ) / false ( within engine/within DLL )
123 * PLUGIN_INFO : true ( within "plugin_info" program ) / false ( everywhere else )
125 #if !defined SYSYNC_ENGINE && !defined SYSYNC_ENGINE_TEST && !defined DBAPI_LINKED && !defined PLUGIN_INFO && !defined DLL_EXPORT
129 #undef _ENTRY_ /* could be defined already here */
131 #define _ENTRY_ ENGINE_ENTRY
137 /* -- MODULE -------------------------------------------------------------------- */
138 /*! Create a module context \<mContext>
139 * This routine will be called as the 2nd call, when the module will be connected.
140 * (The 1st call is a 'Module_Version( 0 )' call outside any context).
142 * It will be called not only once, but once for each session and datastore context,
143 * as defined at the XML config file. This routine can return error 20028 (LOCERR_ALREADY),
144 * if already created. This will be treated not as an error. For this case, it must
145 * return the same \<mContext> as for the former call(s).
147 * NOTE: The module context can exist once and can be shared for all plug-in accesses.
148 * This can either be done with an allocated global variable at the plug-in or
149 * even better using the "GlobContext" structure provided by the SyncML engine.
150 * Please note, that write access to such a common module context structure must
151 * be thread-safe, when accessed from the session or datastore context.
152 * All the 'Module_CreateContext' calls for this module will be called
153 * sequentially by one thread. The plug-in programmer is responsible not to
154 * re-initialize the context for subsequent calls.
156 * If the module name at the XML config file is defined as "aaa!bbb!ccc" it will be passed
157 * as "aaa" to \<moduleName> and "bbb!ccc" to \<subName>. This mechanism can be used to
158 * cascade plug-in modules, where the next module gets "bbb" as \<moduleName> and "ccc" as
159 * \<subName>. The JNI plug-in for Java is using this structure to address the JNI plug-in
160 * and its assigned Java class. Error 20034 (LOCERR_UNKSUBSYSTEM) should be returned in case
161 * the subsystem does not exist, no error if no subsystem has been chosen at all.
164 * @param <mContext> Returns a value, which allows to identify this module context.
165 * Allowed values: Anything except 0, which is reserved for no context.
166 * @param <moduleName> Name of this plug-in
167 * @param <subName> Name of sub module (if available)
168 * @param <mContextName> Name of the (datastore) context, e.g. "contacts";
169 * this string is empty for calll concerning the session.
170 * @param <mCB> DB_Callback structure for module logging
172 * @return error code if context could not be created (e.g. not enough memory)
173 * LOCERR_ALREADY if global module context already exists (not treated as error)
174 * 0 if context successfully created.
176 _ENTRY_ TSyError Module_CreateContext( CContext *mContext, cAppCharP moduleName,
178 cAppCharP mContextName,
183 /*! Get the module's version.
185 * NOTE: The SyncML will take decisions depending on this version number, so
186 * the plug-in developer should not change the values at the delivered sample code.
187 * Plugin_Version( short buildNumber ) of 'SDK_util' should be used.
188 * The \<buildNumber> can be defined by the user.
190 * NOTE: This function can be called by the engine outside any context with
191 * \<mContext> = 0. For this case, any callback is not permitted (as no DB_Callback
194 * @param <mContext> The module context ( 0, if none ).
195 * @return current version as SDK_VERSION_MAJOR | SDK_VERSION_MINOR)
196 * | SDK_SUBVERSION | buildNumber
198 _ENTRY_ CVersion Module_Version( CContext mContext );
202 /*! Get the module's capabilities
203 * Currently the SyncML engine currently understands and supports:
204 * - "plugin_sessionauth"
205 * - "plugin_deviceadmin"
206 * - "plugin_datastoreadmin"
207 * - "plugin_datastore"
209 * If one of these identifiers will be defined as "no" ( e.g. "plugin_sessionauth:no" ),
210 * the according routines will not be connected and used.
212 * NOTE: The \<mCapabilities> can be allocated with "StrAlloc" (SDK_util.h) for C/C++
214 * @param <mContext> The module context.
215 * @param <mCapabilities> Returns the module's capabilities as multiline
216 * aa:bb\<CRLF>cc:dd[\<CRLF>]
219 _ENTRY_ TSyError Module_Capabilities( CContext mContext, appCharP *mCapabilities );
223 /*! The module's config params will be sent to the plug-in.
224 * It can be used for access path definitions or other things.
225 * The \<plugin_params> can be defined individually for each session and datastore.
226 * The SyncML engine checks the syntax, but not the content.
227 * This routine should return an error 20010 (LOCERR_CFGPARSE), if one of
228 * these parameters is not supported.
230 * EXAMPLE: Definition at XML config file:\n
232 * \<datapath>/var/log/sysync\</datapath>\n
233 * \<ultimate_answer>42\</ultimate_answer>\n
236 * will be passed as:\n
237 * "datapath:/var/log/sysync\n
238 * ultimate_answer:42"
240 * NOTE: Module_PluginParams will be called ALWAYS for each module context,
241 * even if no plug-in parameter is defined. This allows to react consistently
242 * on parameters, which are not always available.
244 * @param <mContext> The module context.
245 * @param <mConfigParams> The plugin params as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
246 * @param <engineVersion> The SyncML engine's version
249 _ENTRY_ TSyError Module_PluginParams( CContext mContext, cAppCharP mConfigParams,
250 CVersion engineVersion );
254 /*! Disposes memory, which has been allocated within the module context.
255 * (At the moment this is only the capabilities string).
256 * 'Module_DisposeObj' can occur at any time within \<mContext>.
258 * NOTE: - If \<mCapabilities> has been allocated with "StrAlloc", use "Str_Dispose"
259 * (SDK_util.h) to release the memory again.
260 * - If it is defined as const within the plugin module (the module
261 * itself knows about !), this routine can be implemented empty.
263 * @param <mContext> The module context.
264 * @param <memory> Dispose allocated memory.
267 _ENTRY_ void Module_DisposeObj( CContext mContext, void* memory );
271 /*! This routine will be called as the last call, before this module is disconnected.
272 * The SyncML engine will call 'Module_DisposeObj' (if required) before this call
274 * NOTE: This routine will be called ONLY, if the server stops in a controlled way.
275 * Its good programming practice not to wait for this 'DeleteContext' call.
277 * @param <mContext> The module context.
280 _ENTRY_ TSyError Module_DeleteContext( CContext mContext );
285 /* -- SESSION ------------------------------------------------------------------- */
286 /*! By default the session context will be handled by the ODBC interface.
287 * The session context of this plug-in module will be used only,
288 * if \<server type="plugin"> and \<plugin_module> is defined
289 * ( \<plugin_module>name_of_the_plugin\</plugin_module> ).
290 * \<plugin_params> can be defined individually.
292 * @param <sContext> Returns a value, which allows to identify this session context.
293 * @param <sessionName> Name of this session
294 * @param <sCB> DB_Callback structure for session logging
296 * @result error code, if context could not be created (e.g. not enough memory)
297 * 0 if context successfully created,
299 * Flags (at the XML config file):
300 * - \<plugin_deviceadmin>yes\</plugin_deviceadmin>: "Session_CheckDevice", "Session_GetNonce"
301 * "Session_SaveNonce" and
302 * "Session_SaveDeviceInfo" will be used.
304 * - \<plugin_sessionauth>yes\</plugin_sessionauth>: "Session_PasswordMode",
305 * "Session_Login" and "Session_Logout" will be used.
307 _ENTRY_ TSyError Session_CreateContext( CContext *sContext, cAppCharP sessionName,
312 /*! This function adapts itemData
314 * @param <sContext> The session context
315 * @param <sItemData1> The 1st item's data
316 * @param <sItemData2> The 2nd item's data
317 * @param <sLocalVars> The local vars
318 * @param <sIdentifier> To identify, where it is called
322 * NOTE: The memory for adapted strings must be allocated locally.
323 * The SyncML engine will call 'DisposeObj' later, to release again its memory.
324 * One or more strings can be returned unchanged as well.
326 _ENTRY_ TSyError Session_AdaptItem( CContext sContext, appCharP *sItemData1,
327 appCharP *sItemData2,
328 appCharP *sLocalVars,
329 uInt32 sIdentifier );
332 /*! Check the database entry of \<aDeviceID> and return its \<nonce> string.
333 * If \<aDeviceID> is not yet available at the plug-in, return "" for \<nonce>
335 * @param <sContext> The session context
336 * @param <aDeviceID> The assigned device ID string
337 * @param <sDevKey> The device key string (will be used for datastore accesses later)
338 * @param <nonce> The nonce string of the last session
339 * If \<aDeviceID> is not yet available, return "" for \<nonce>
342 * @result error code 403 (Forbidden), if plugin_deviceadmin is not supported;
345 * USED ONLY WITH \<plugin_deviceadmin>
347 _ENTRY_ TSyError Session_CheckDevice( CContext sContext, cAppCharP aDeviceID,
352 /*! Get a new nonce from the database. If this routine returns an error,
353 * the SyncML engine will create its own nonce.
355 * @param <sContext> The session context
356 * @param <nonce> A valid new nonce value (for the assigned device ID).
358 * @return error code 404 (NotFound), if no \<nonce> has been generated;
359 * 0, if a valid \<nonce> has been generated
361 * USED ONLY WITH \<plugin_deviceadmin>
363 _ENTRY_ TSyError Session_GetNonce( CContext sContext, appCharP *nonce );
367 /*! Save the new nonce (which will be expected to be returned in the
368 * next session for this device ID.
370 * @param <sContext> The session context
371 * @param <nonce> New \<nonce> for the next session (of the assigned device ID)
373 * @result error code 403 (Forbidden), if plugin_deviceadmin is not supported;
376 * USED ONLY WITH \<plugin_deviceadmin>
378 _ENTRY_ TSyError Session_SaveNonce( CContext sContext, cAppCharP nonce );
382 /*! Save the device info for \<sContext>
384 * @param <sContext> The session context
385 * @param <aDeviceInfo> More information about the assigned device (for DB and logging)
387 * @result error code 403 (Forbidden), if plugin_deviceadmin is not supported;
390 * USED ONLY WITH \<plugin_deviceadmin>
392 _ENTRY_ TSyError Session_SaveDeviceInfo( CContext sContext, cAppCharP aDeviceInfo );
396 /*! Get the current DB time of \<sContext>
398 * @param <sContext> The session context
399 * @param <currentDBTime> The current time of the plugin's DB (as ISO8601 format).
401 * @result error code 403 (Forbidden), if plugin_deviceadmin is not supported;
402 * 404 (NotFound), if not available -> the engine creates its own time
405 _ENTRY_ TSyError Session_GetDBTime( CContext sContext, appCharP *currentDBTime );
409 /*--------------------------------------------------------------------------------*/
410 /*! Get the password mode.
411 * There are currently 4 different password modes supported.
413 * @param <sContext> The session context
416 * - Password_ClrText_IN : 'SessionLogin' will get clear text password
417 * - Password_ClrText_OUT : " must return clear text password
418 * - Password_MD5_OUT : " must return MD5 coded password
419 * - Password_MD5_Nonce_IN: " will get MD5B64(MD5B64(user:pwd):nonce)
421 * USED ONLY WITH \<plugin_sessionauth>
423 _ENTRY_ sInt32 Session_PasswordMode( CContext sContext );
426 /*! Get \<sUsrKey> of \<sUsername>,\<sPassword> in the session context.
428 * @param <sContext> The session context
429 * @param <sUsername> The user name ...
430 * @param <sPassword> ... and the password. \<sPassword> is an input parameter
431 for 'Password_ClrTxt_IN' mode and an output parameter for
432 * 'Password_ClrText_OUT' and 'Password_MD5_OUT' modes.
433 * @param <sUsrKey> Returns the internal reference key, which will be passed to
434 * to the datastore contexts later.
436 * @result error code 403 (Forbidden), if plugin_sessionauth is not supported;
439 * USED ONLY WITH \<plugin_sessionauth>
441 _ENTRY_ TSyError Session_Login( CContext sContext, cAppCharP sUsername,
446 /*! Logout for this session context
448 * @param <sContext> The session context
450 * @result error code 403 (Forbidden), if plugin_sessionauth is not supported;
453 * USED ONLY WITH \<plugin_sessionauth>
455 _ENTRY_ TSyError Session_Logout( CContext sContext );
459 /*! Disposes memory, which has been allocated within the session context.
460 * 'Session_DisposeObj' can occur at any time within \<sContext>.
462 * @param <sContext> The session context.
463 * @param <memory> Dispose allocated memory.
467 _ENTRY_ void Session_DisposeObj( CContext sContext, void* memory );
471 /*! Due to the architecture of the SyncML engine, the system may run in a multithread
472 * environment. The consequence is that each routine of this plugin module can be
473 * called by a different thread. Normally this is not a problem, nevertheless
474 * this routine notifies about thread changes in \<sContext>.
475 * It can be ignored ( =implemented empty), if not really needed.
477 * @param <sContext> The session context
480 _ENTRY_ void Session_ThreadMayChangeNow( CContext sContext );
484 /*! Writes the context of all items to dbg output path
485 * This routine is implemented for debug purposes only and will NOT BE CALLED by the
486 * SyncML engine. Can be implemented empty
488 * @param <sContext> The session context
489 * @param <allFields> true : all fields, also empty ones, will be displayed;
490 * false: only fields <> "" will be shown
491 * @param <specificItem> "" : all items will be shown;
492 * else shows the \<specificItem>
496 _ENTRY_ void Session_DispItems( CContext sContext, bool allFields, cAppCharP specificItem );
500 /*! Delete a session context.
501 * No access to \<sContext> will be done after this call
503 * @param <sContext> The session context
504 * @return error code, if context could not be deleted.
506 _ENTRY_ TSyError Session_DeleteContext( CContext sContext );
511 /* -- OPEN ---------------------------------------------------------------------- */
512 /*! This routine is called to create a new context for a datastore access.
513 * It must allocate all resources for this context and initialize the \<aContext>
514 * parameter with a value that allows re-identifying the context.
515 * \<aContext> can either be a pointer to the local context structure or any key
516 * value which allows to re-identify the context later.
517 * Subsequent calls related to this context will pass the \<aContext> value as returned
518 * from CreateContext. The context must be valid until 'DeleteContext' is called.
519 * \<plugin_params> can be defined individually.
521 * NOTE: The SyncML engine treats \<aContext> simply as a key. The only condition
522 * is uniqueness for all datastore contexts. Even \<aContext> = 0 can be used.
524 * @param <aContext> Returns a value, which allows to identify this datastore context.
525 * @param <aContextName> Allows to identify the context, if more than one must be
526 * handled. \<contextName> is defined at the XML configuration.
527 * @param <aCB> DB_Callback structure for datatstore logging.
528 * @param <sDevKey> The result of 'Session_CheckDevice' comes in here.
529 * @param <sUsrKey> The result of 'Session_Login' comes in here.
531 * @return error code, if context could not be created (e.g. not enough memory),
532 * 0 if context successfully created.
534 _ENTRY_ TSyError CreateContext( CContext *aContext, cAppCharP aContextName, DB_Callback aCB,
539 /*! This function asks for specific context configurations
541 * @param <aContext> The datastore context
542 * @param <aSupportRules> The SyncML sends a list of support rules.
543 * This function has to reply, up to which rule,
544 * contexts are supported (and switched on now).
545 * Data is formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
547 * @return Up to \<n> fields are supported (and switched on) for this context.
548 * If 0 will be returned, no field of \<aSupportRules> is supported.
551 _ENTRY_ uInt32 ContextSupport( CContext aContext, cAppCharP aSupportRules );
555 /*! This function asks for filter support.
557 * @param <aContext> The datastore context
558 * @param <aFilterRules> The SyncML sends a list of filter rules.
559 * This function has to reply, up to which rule,
560 * filters are supported (and switched on now).
561 * Data is formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
563 * @return Up to \<n> filters are supported (and switched on) for this context
564 * If 0 will be returned, no field of \<aFilterRules> are supported.
566 _ENTRY_ uInt32 FilterSupport( CContext aContext, cAppCharP aFilterRules );
570 /* -- GENERAL ------------------------------------------------------------------- */
571 /*! Due to the architecture of the SyncML engine, the system may run in a multithread
572 * environment. The consequence is that each routine of this API module can be
573 * called by a different thread. Normally this is not a problem, nevertheless
574 * this routine notifies about thread changes in \<aContext>.
575 * It can be ignored ( =implemented empty), if not really needed.
577 * @param <aContext> The datastore context.
581 _ENTRY_ void ThreadMayChangeNow( CContext aContext );
585 /*! This functions writes \<logData> for this context
586 * Can be implemented empty, if not needed.
588 * @param <aContext> The datastore context.
589 * @param <logData> Logging information, formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
593 _ENTRY_ void WriteLogData( CContext aContext, cAppCharP logData );
597 /*! Writes the context of all items to dbg output path
598 * This routine is implemented for debug purposes only and will NOT BE CALLED by the
599 * SyncML engine. Can be implemented empty, if not needed.
601 * @param <aContext> The datastore context.
603 * - true : all fields, also empty ones, will be displayed;
604 * - false: only fields <> "" will be shown
605 * @param <specificItem>
606 * - "" : all items will be shown;
607 * - else : shows the \<specificItem>
611 _ENTRY_ void DispItems( CContext aContext, bool allFields, cAppCharP specificItem );
615 /* -- ADMINISTRATION ------------------------------------------------------------ */
616 /* This section contains the 'admin read' and 'admin write' routines. */
618 /*! This function gets the stored information about the record with the four paramters:
619 * \<sDevKey>, \<sUsrKey>, \<aLocDB>, \<aRemDB>.
621 * - \<plugin_deviceadmin>yes\</plugin_deviceadmin>: Admin/Map routines will be used.
623 * @param <aContext> The datastore context
624 * @param <aLocDB> Name of the local DB
625 * @param <aRemDB> Name of the remote DB
626 * @param <adminData> The data, saved with the last 'SaveAdminData' call
628 * @return error code 404 (NotFound), if record is not (yet) available,
629 * 0 (no error) if admin data found
631 * NOTE: \<sDevKey> and \<sUsrKey> have been passed with 'CreateContext' already.
632 * The plug-in module must have stored them within the datastore context.
634 * USED ONLY WITH \<plugin_datastoredadmin>
636 _ENTRY_ TSyError LoadAdminData( CContext aContext, cAppCharP aLocDB,
637 cAppCharP aRemDB, appCharP *adminData );
641 /*! This functions stores the new \<adminData> for this context
643 * @param <aContext> The datastore context
644 * @param <adminData> The new set of admin data to be stored, will be loaded again
645 * with the next 'LoadAdminData' call.
647 * @result error code, if data could not be saved (e.g. not enough memory);
648 * 0 if successfully created.
650 * USED ONLY WITH \<plugin_datastoredadmin>
652 _ENTRY_ TSyError SaveAdminData( CContext aContext, cAppCharP adminData );
656 /*! Map table handling: Get the next map item of this context.
657 * If \<aFirst> is true, the routine must start to return the first element
659 * @param <aContext> The datastore context
660 * @param <mID> MapID ( with \<localID>,\<remoteID>, <flags> and \<ident> ).
661 * @param <aFirst> Starting with the first MapID. When creating a context,
662 * the first call will get the first MapID, even if \<aFirst>
666 * - true: as long as there is a MapID available, which must be assigned to <mID>
667 * - false: if there is no more MapID. Nothing must be assigned to <mID>
669 * USED ONLY WITH \<plugin_datastoredadmin>
671 _ENTRY_ bool ReadNextMapItem( CContext aContext, MapID mID, bool aFirst );
674 /*! Map table handling: Insert a map item of this context
676 * @param <aContext> The datastore context
677 * @param <mID> MapID ( with \<localID>,\<remoteID>, \<flags> and \<ident> ).
679 * @return error code, if this MapID can't be inserted, or if already existing
681 * USED ONLY WITH \<plugin_datastoredadmin>
683 _ENTRY_ TSyError InsertMapItem( CContext aContext, cMapID mID );
686 /*! Map table handling: Update a map item of this context
688 * @param <aContext> The datastore context
689 * @param <mID> MapID ( with \<localID>,\<remoteID>, \<flags> and \<ident> ).
690 * If there is already a MapID element with \<localID> and \<ident>,
691 * it will be updated, else created.
693 * @return error code, if this MapID can't be updated (e.g. not yet existing).
695 * USED ONLY WITH \<plugin_datastoredadmin>
697 _ENTRY_ TSyError UpdateMapItem( CContext aContext, cMapID mID );
700 /*! Map table handling: Delete a map item of this context
702 * @param <aContext> The datastore context
703 * @param <mID> MapID ( with \<localID>,\<remoteID>, \<flags> and \<ident> ).
705 * @return error code, if this MapID can't deleted,
706 * or if this MapID does not exist.
708 * USED ONLY WITH \<plugin_datastoredadmin>
710 _ENTRY_ TSyError DeleteMapItem( CContext aContext, cMapID mID );
715 /* -- READ ---------------------------------------------------------------------- */
716 /*! This routine initializes reading from the database
717 * StartDataRead must prepare the database to return the objects of this context.
719 * @param <aContext> The datastore context.
720 * @param <lastToken> The value which has been returned by this module
721 * at the last "EndDataWrite" call will be given.
722 * It will be "", when called the first time.
723 * Normally this token is an ISO8601 formatted string
724 * which represents the module's current time (at the
725 * beginning of a session). It will be used to decide at
726 * 'ReadNextItem' whether a record has been changed.
727 * @param <resumeToken> Token for Suspend/Resume mode.
731 _ENTRY_ TSyError StartDataRead( CContext aContext, cAppCharP lastToken,
732 cAppCharP resumeToken );
736 /*! This routine reads the next ItemID from the database.
737 * \<allfields> of 'ContextSupport' ( "ReadNextItem:allfields" ) and
738 * \<aFilterRules> of 'FilterSupport' must be considered.
739 * If \<aFirst> is true, the routine must return the first element (again).
741 * @param <aContext> The datastore context.
742 * @param <aID> The assigned ItemID in the database;
743 * will be ignored by the SyncML engine, if \<aStatus> = 0
744 * @param <aItemData> The data, formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>];
745 * will be ignored by the SyncML engine, if \<aStatus> = 0
747 * - ReadItem_EOF ( =0 ) for none ( =eof ),
748 * - ReadItem_Changed ( =1 ) for a changed item,
749 * - ReadItem_Unchanged ( =2 ) for unchanged item.
750 * - ReadItem_Resumed ( =3 ) for a changed item (since resumed)
752 * - true: the routine must return the first element
753 * - false: the routine must return the next element
755 * @return error code, if not ok. No datasets found is a success as well !
758 * NOTE: The memory for \<aID> and \<aItemData> must be allocated locally.
759 * The SyncML engine will call 'DisposeObj' later for these objects to
760 * release the memory again. It needn't to be allocated, if \<aStatus>
763 * NOTE: By default, the SyncML engine asks for \<aID> only.
764 * \<aItemData> can be returned, if anyway available or
765 * \<aItemData> must be returned, if the engine asks for it
766 * (when calling "ReadNextItem:allfields" at 'ContextSupport' with \<allfields>).
768 _ENTRY_ TSyError ReadNextItem ( CContext aContext, ItemID aID, appCharP *aItemData,
769 sInt32 *aStatus, bool aFirst );
771 /*! This is the equivalent to 'ReadNextItem', but using a key instead of a data string */
772 _ENTRY_ TSyError ReadNextItemAsKey( CContext aContext, ItemID aID, KeyH aItemKey,
773 sInt32 *aStatus, bool aFirst );
777 /*! This routine reads the contents of a specific ItemID \<aID> from the database.
779 * @param <aContext> The datastore context.
780 * @param <aID> The assigned ItemID in the database
781 * @param <aItemData> Returns the data, formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
783 * @return error code, if not ok ( e.g. invalid \<aItemID> )
786 * NOTE: The memory for \<aItemData> must be allocated locally.
787 * The SyncML engine will call 'DisposeObj' later for \<aItemData>,
788 * to release again its memory.
790 _ENTRY_ TSyError ReadItem ( CContext aContext, cItemID aID, appCharP *aItemData );
792 /*! This is the equivalent to 'ReadItem', but using a key instead of a data string */
793 _ENTRY_ TSyError ReadItemAsKey( CContext aContext, cItemID aID, KeyH aItemKey );
797 /*! This routine reads the specific binary logic block \<aID>,\<aBlobID>
800 * @param <aContext> The datastore context.
801 * @param <aID> ItemID ( with \<item>,\<parent> ).
802 * @param <aBlobID> The assigned ID of the blob.
804 * @param <aBlkPtr> Position and size (in bytes) of the blob block.
806 * - Input: Maximum size (in bytes) of the blob block to be read.
807 * If \<blkSize> is 0, the result size is not limited.
808 * - Output: Size (in bytes) of the blob block.
809 * \<blkSize> must not be larger than its input value.
810 * @param <aTotSize> Total size of the blob (in bytes), can be also 0,
811 * if not available, e.g. for a stream.
813 * @param <aFirst> (Input)
814 * - true : Engine asks for the first block of this blob.
815 * - false: Engine asks for the next block of this blob.
817 * @param <aLast> (Output)
818 * - true : This is the last part (or the whole) blob.
819 * - false: More blocks will follow.
821 * @return error code, if not ok ( e.g. invalid \<aItemID>,\<aBlobID> )
824 * NOTE 1) The memory at \<blkPtr>,\<blkSize> must be allocated locally.
825 * The SyncML engine will call 'DisposeObj' later for \<blkPtr>,
826 * to release the memory.
828 * NOTE 2) Empty blobs are allowed, \<blkSize> and \<totSize> must be set to 0,
829 * \<blkPtr> can be undefined, \<aLast> must be true.
830 * No 'DisposeObj' call is required for this case.
832 * NOTE 3) The SyncML engine can change to read another blob before
833 * having read the whole blob. It will never resume reading of this
834 * incomplete blob, but start reading again with \<aFirst> = true.
836 _ENTRY_ TSyError ReadBlob( CContext aContext, cItemID aID, cAppCharP aBlobID,
837 appPointer *aBlkPtr, memSize *aBlkSize,
839 bool aFirst, bool *aLast );
843 /*! This routine terminates the read from database phase
844 * It can be used e.g. for termination of a transaction.
845 * In standard case it can be implemented empty, returning simply a value LOCERR_OK = 0.
847 * @param <aContext> The datastore context.
850 _ENTRY_ TSyError EndDataRead( CContext aContext );
855 /* -- WRITE --------------------------------------------------------------------- */
856 /*! This routine initializes writing to the database
858 * @param <aContext> The datastore context.
859 * @return error code, if not ok (e.g. invalid select options)
861 _ENTRY_ TSyError StartDataWrite( CContext aContext );
865 /*! This routine inserts a new dataset to the database. The assigned
866 * new ItemID \<aId> will be returned.
868 * @param <aContext> The datastore context.
869 * @param <aItemData> The data, formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
870 * @param <aID> Database key of the new dataset.
873 * - LOCERR_OK ( =0 ), if successful
874 * - DB_DataMerged ( =207 ), if successful, but "ReadItem" requested to
875 * inform about updates
876 * - DB_Forbidden ( =403 ), if \<aItemData> can't be resolved
877 * - DB_Full ( =420 ), if not enough space in the DB
878 * - ... or any other SyncML error code, see Reference Manual
880 * NOTE: The memory for \<aItemID> must be allocated locally.
881 * The SyncML engine will call 'DisposeObj' later for \<aItemID>,
882 * to release the memory
885 _ENTRY_ TSyError InsertItem ( CContext aContext, cAppCharP aItemData, ItemID aID );
887 /*! This is the equivalent to 'InsertItem', but using a key instead of a data string */
888 _ENTRY_ TSyError InsertItemAsKey( CContext aContext, KeyH aItemKey, ItemID aID );
892 /*! This routine updates an existing dataset of the database
894 * @param <aContext> The datastore context.
895 * @param <aItemData> The data, formatted as multiline aa:bb\<CRLF>cc:dd[\<CRLF>]
896 * @param <aID> Database key of dataset to be updated
898 * - Input: NULL is assigned as default value to
899 * \<updID.item> and \<updID.parent>.
900 * - Output: The updated database key for \<aID>.
901 * Can be NULL, if the same as \<aID>
904 * - LOCERR_OK ( =0 ), if successful
905 * - DB_Forbidden ( =403 ), if \<aItemData> can't be resolved
906 * - DB_NotFound ( =404 ), if unknown \<aID>
907 * - DB_Full ( =420 ), if not enough space in the DB
908 * - ... or any other SyncML error code, see Reference Manual
911 * NOTE: \<updID> must either contain NULL references ( if the same as \<aID> ),
912 * or the memory for \<updID.item>,\<updID.parent> must be allocated locally.
913 * The SyncML engine will call 'DisposeObj' later for \<updID.item> and
914 * \<updID.parent> to release the memory.
915 * \<updID.parent> can be NULL, if the hierarchical model is not supported.
917 _ENTRY_ TSyError UpdateItem ( CContext aContext, cAppCharP aItemData, cItemID aID,
920 /*! This is the equivalent to 'UpdateItem', but using a key instead of a data string */
921 _ENTRY_ TSyError UpdateItemAsKey( CContext aContext, KeyH aItemKey, cItemID aID,
926 /*! This routine moves \<aID.item> from \<aID.parent> to \<newParID>
928 * @param <aContext> The datastore context.
929 * @param <aID> ItemID ( with \<item>,\<parent> ) to be moved.
930 * @param <newParID> New parent ID for \<aID>
933 * - LOCERR_OK ( =0 ), if successful
934 * - DB_NotFound ( =404 ), if unknown \<newParID>
935 * - DB_Full ( =420 ), if not enough space in the DB
936 * - ... or any other SyncML error code, see Reference Manual
938 _ENTRY_ TSyError MoveItem( CContext aContext, cItemID aID, cAppCharP newParID );
942 /*! This routine deletes a dataset from the database
944 * @param <aContext> The datastore context.
945 * @param <aID> ItemID ( with \<item>,\<parent> ) to be deleted.
948 * - LOCERR_OK ( =0 ), if successful
949 * - DB_NotFound ( =404 ), if unknown \<aItemID>
950 * - ... or any other SyncML error code, see Reference Manual
952 _ENTRY_ TSyError DeleteItem( CContext aContext, cItemID aID );
957 /*! This routine updates a temporary <aID> to an <updID> at the end
958 * For cached systems which assign IDs at the end of a run.
960 * @param <aContext> The datastore context.
961 * @param <aID> Database key of dataset to be updated
963 * - Input: NULL is assigned as default value to
964 * \<updID.item> and \<updID.parent>.
965 * - Output: The updated database key for \<aID>.
966 * Can be NULL, if the same as \<aID>
969 * - LOCERR_OK ( =0 ), if successful
970 * - DB_Forbidden ( =403 ), if \<aItemData> can't be resolved
971 * - DB_NotFound ( =404 ), if unknown \<aID>
972 * - LOCERR_NOTIMP ( =20030 ), if no finalizing is needed at all
973 * - ... or any other SyncML error code, see Reference Manual
975 * NOTE: \<updID> must either contain NULL references ( if the same as \<aID> ),
976 * or the memory for \<updID.item> must be allocated locally.
977 * The SyncML engine will call 'DisposeObj' later for \<updID.item>
978 * to release the memory. \<updID.parent>should be always NULL.
980 _ENTRY_ TSyError FinalizeLocalID( CContext aContext, cItemID aID, ItemID updID );
985 /*! This routine deletes all datasets from the database
987 * @param <aContext> The datastore context.
990 * - LOCERR_OK ( =0 ), if successful
991 * - LOCERR_NOTIMP ( =20030 ). For this case, the engine removes all items directly
992 * - ... or any other SyncML error code, see Reference Manual
994 _ENTRY_ TSyError DeleteSyncSet( CContext aContext );
999 /*! This routine writes the specific binary logic block \<blobID> to the database.
1001 * @param <aContext> The datastore context.
1002 * @param <aID> ItemID ( with \<item>,\<parent> ).
1003 * @param <aBlobID> The assigned ID of the blob.
1006 * @param <aBlkSize> Position and size (in bytes) of the blob block.
1007 * @param <aTotSize> Total size of the blob (in bytes),
1008 * Can be also 0, if not available, e.g. for a stream.
1011 * - true : this is the first block of the blob.
1012 * - false: this is the next block.
1014 * - true : this is the last block.
1015 * - false: more blocks will follow.
1017 * @return error code, if not ok ( e.g. invalid \<aID>,\<aBlobID> )
1019 * NOTE: Empty blobs are possible, \<blkSize> and \<totSize> will be set to 0,
1020 * \<blkPtr> will be NULL, \<aFirst> and \<aLast> will be true.
1022 _ENTRY_ TSyError WriteBlob( CContext aContext, cItemID aID, cAppCharP aBlobID,
1023 appPointer aBlkPtr, memSize aBlkSize,
1025 bool aFirst, bool aLast );
1028 /*! This routine deletes the specific binary logic block \<blobID> at the database.
1030 * @param <aContext> The datastore context.
1031 * @param <aID> ItemID ( with \<item>,\<parent> ).
1032 * @param <aBlobID> The assigned ID of the blob.
1034 * @return error code, if not ok ( e.g. invalid \<aID>,\<aBlobID> )
1036 _ENTRY_ TSyError DeleteBlob( CContext aContext, cItemID aID, cAppCharP aBlobID );
1039 /*! Advises the database to finsish the running transaction
1041 * @param <aContext> The datastore context.
1043 * - true: All former actions were successful,
1044 * so the database can commit
1045 * - false: The transaction was not successful,
1046 * so the database may rollback or ignore the transaction.
1048 * @param <newToken> An internally generated string value, which
1049 * will be used to identify changed database records.
1050 * It is normally an ISO8601 formatted string, which
1051 * represents the module's current time (at the
1052 * time the 'StartDataRead' of this context has been
1053 * called). All changed records of the currrent context
1054 * must get this token as timestamp as as well.
1055 * The SyncML engine will return this value with the
1056 * 'StartDataRead' call within the next session.
1057 * It must return NULL in case of no \<success>.
1059 * @return error code, if operation can't be performed. No \<success> is not an error.
1062 * NOTE: By default, the SyncML engine expects an ISO8601 string for \<newToken>.
1063 * But the SyncML engine can be configured to treat this value completely
1064 * opaque, if implemented in a different way.
1066 * The \<newToken> must be allocated locally and will be
1067 * disposed with a 'DisposeObj' call later by the SyncML engine.
1069 _ENTRY_ TSyError EndDataWrite( CContext aContext, bool success, appCharP *newToken );
1073 /* ---- ADAPT ITEM -------------------------------------------------------------- */
1074 /*! This function adapts aItemData
1076 * @param <aContext> The datastore context
1077 * @param <aItemData1> The 1st item's data
1078 * @param <aItemData2> The 2nd item's data
1079 * @param <aLocalVars> The local vars
1080 * @param <aIdentifier> To identify, where it is called
1082 * @return error code
1084 * NOTE: The memory for adapted strings must be allocated locally.
1085 * The SyncML engine will call 'DisposeObj' later, to release again its memory.
1086 * One or more strings can be returned unchanged as well.
1088 _ENTRY_ TSyError AdaptItem( CContext aContext, appCharP *aItemData1,
1089 appCharP *aItemData2,
1090 appCharP *aLocalVars,
1091 uInt32 aIdentifier );
1094 /* -- DISPOSE / CLOSE ----------------------------------------------------------- */
1095 /*! Disposes memory, which has been allocated within the datastore context.
1096 * 'DisposeObj' can occur at any time within \<aContext>.
1098 * @param <aContext> The datastore context.
1099 * @param <memory> Dispose allocated memory.
1104 _ENTRY_ void DisposeObj( CContext aContext, void* memory );
1108 /*! This routine is called to delete a context, that was previously created with
1109 * 'CreateContext'. The DB Module must free all resources related to this context.
1110 * No calls with \<aContext> will be done after calling this routine, so the
1111 * assigned structure, allocated at 'CreateContext' can be released here.
1113 * @param <aContext> The datastore context.
1115 * @result error code, if context could not be deleted ( e.g. not existing \<aContext> ).
1117 _ENTRY_ TSyError DeleteContext( CContext aContext );