libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

data_sync_callbacks.c
1 /*
2 * libsyncml - A syncml protocol implementation
3 * Copyright (C) 2008-2009 Michael Bell <michael.bell@opensync.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21 #include "data_sync_callbacks.h"
22 #include "libsyncml/syncml_internals.h"
23 #include "libsyncml/sml_support.h"
24 #include "libsyncml/sml_error_internals.h"
25 #include <string.h>
26 #include <strings.h>
27 #include "defines.h"
28 #include "data_sync_devinf.h"
29 #include "libsyncml/objects/sml_ds_server_internals.h"
30 #include "libsyncml/sml_manager_internals.h"
31
32 //#include "syncml_common.h"
33 //#include "syncml_callbacks.h"
34 //#include "syncml_vformat.h"
35 //#include "syncml_devinf.h"
36 //#include "syncml_ds_client.h"
37 //#include "syncml_ds_server.h"
38
39 /* **************************************** */
40 /* ***** Management Callbacks ***** */
41 /* **************************************** */
42
43 void smlDataSyncEventCallback(
44 SmlManager *manager,
45 SmlManagerEventType type,
46 SmlSession *session,
47 SmlError *error,
48 void *userdata)
49 {
50 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, manager, type, session, error, userdata);
51 SmlDataSyncObject *dsObject = userdata;
52 smlAssert(dsObject);
53 GList *o = NULL;
54 /* FIXME: Is this lock really needed? */
55 /* FIXME: Who is allowed to call smlManagerDispatch? */
56 /* FIXME: The SmlManager must be synchronized and not the callback. */
57 g_mutex_lock(dsObject->managerMutex);
58
59 switch (type) {
60 case SML_MANAGER_SESSION_FLUSH:
61 case SML_MANAGER_CONNECT_DONE:
62 smlTrace(TRACE_INTERNAL, "%s: ignored event %d ", __func__, type);
63 dsObject->internalState = SML_DATA_SYNC_STATE_CONNECTED;
64 break;
65 case SML_MANAGER_SESSION_ESTABLISHED:
66 smlTrace(TRACE_INTERNAL, "%s: session established", __func__);
67 dsObject->internalState = SML_DATA_SYNC_STATE_SESSION_READY;
68 smlDataSyncSendEvent(
69 dsObject, SML_DATA_SYNC_EVENT_CONNECT,
70 dsObject->eventUserdata, NULL);
71 break;
72 case SML_MANAGER_DISCONNECT_DONE:
73 smlTrace(TRACE_INTERNAL, "%s: connection with device has ended", __func__);
74 /* If the transport was never connected
75 * then it is useless to handle the disconnect
76 * event.
77 */
78 if (dsObject->internalState < SML_DATA_SYNC_STATE_CONNECTED)
79 {
80 smlTrace(TRACE_INTERNAL,
81 "%s: ignored disconnect because never connected",
82 __func__);
83 break;
84 }
85 /* anchor caching is optional */
86 if (dsObject->setAnchorCallback)
87 {
88 o = dsObject->datastores;
89 for (; o; o = o->next) {
90 SmlDataSyncDatastore *datastore = o->data;
91 /* write new sync anchors */
92 char *anchor = g_strdup_printf(
93 "localanchor%s",
94 smlDsSessionGetLocation(datastore->session));
95 if (!dsObject->setAnchorCallback(
96 dsObject,
97 anchor, datastore->localNext,
98 dsObject->setAnchorUserdata,
99 &error))
100 goto error;
101 anchor = g_strdup_printf(
102 "remoteanchor%s",
103 smlDsSessionGetLocation(datastore->session));
104 if (!dsObject->setAnchorCallback(
105 dsObject,
106 anchor, datastore->remoteNext,
107 dsObject->setAnchorUserdata,
108 &error))
109 goto error;
110 }
111 }
112
113 dsObject->internalState = SML_DATA_SYNC_STATE_DISCONNECTED;
114 smlDataSyncSendEvent(
115 dsObject, SML_DATA_SYNC_EVENT_DISCONNECT,
116 dsObject->eventUserdata, NULL);
117 smlDataSyncSendEvent(
118 dsObject, SML_DATA_SYNC_EVENT_FINISHED,
119 dsObject->eventUserdata, NULL);
120 break;
121 case SML_MANAGER_TRANSPORT_ERROR:
122 smlTrace(TRACE_INTERNAL,
123 "There was an error in the transport: %s",
124 smlErrorPrint(&error));
125 if (SML_DATA_SYNC_STATE_CONNECTED <= dsObject->internalState &&
126 dsObject->internalState < SML_DATA_SYNC_STATE_DISCONNECTED) {
127 if (dsObject->internalState < SML_DATA_SYNC_STATE_DISCONNECT_IN_PROGRESS) {
128 dsObject->internalState = SML_DATA_SYNC_STATE_DISCONNECT_IN_PROGRESS;
129 SmlError *locerror = NULL;
130 SmlLink *link_ = smlManagerSessionGetLink(
131 dsObject->manager,
132 dsObject->session,
133 &locerror);
134 if (link_ || !locerror)
135 smlTransportDisconnect(
136 dsObject->tsp,
137 link_,
138 &locerror);
139 if (link_)
140 smlLinkDeref(link_);
141 /* error is already tracked.
142 * So locerror can be ignored.
143 */
144 if (locerror)
145 smlErrorDeref(&locerror);
146 /* It is not a good idea to wait for the
147 * disconnect here. First this is an
148 * asynchronous software so it is always
149 * bad if the software blocks. Second it
150 * is dangerous to call smlManagerDispatch
151 * here because an error during these
152 * dispatch activities can lead to another
153 * error which overwrites the original
154 * error.
155 *
156 * Deadlock must be handled in another way.
157 * The SyncML protocol is usually already
158 * broken if this happens (TRANSPORT_ERROR).
159 *
160 * So yes, it is important to disconnect
161 * and no, it must not run dispatch.
162 */
163 } else {
164 /* disconnect failed */
165 dsObject->internalState = SML_DATA_SYNC_STATE_DISCONNECTED;
166 }
167 }
168 goto error;
169 break;
170 case SML_MANAGER_SESSION_NEW:
171 smlTrace(TRACE_INTERNAL, "%s: Just received a new session with ID %s",
172 __func__, VA_STRING(smlSessionGetSessionID(session)));
173 if (dsObject->session) {
174 smlTrace(TRACE_INTERNAL,
175 "%s: WARNING: There was an old session %s in the environment.",
176 __func__, VA_STRING(smlSessionGetSessionID(dsObject->session)));
177 smlSessionUnref(dsObject->session);
178 dsObject->session = NULL;
179 }
180 smlSessionUseStringTable(session, dsObject->useStringTable);
181 smlSessionUseOnlyReplace(session, dsObject->onlyReplace);
182 smlSessionUseNumberOfChanges(session, dsObject->useNumberOfChanges);
183
184 smlTrace(TRACE_INTERNAL, "%s: maxObjSize %d",
185 __func__, dsObject->maxObjSize);
186
187 dsObject->session = session;
188 smlSessionRef(session);
189
190 /* authentication management for OMA DS clients*/
191 if (dsObject->dsType == SML_SESSION_TYPE_CLIENT &&
192 (dsObject->username || dsObject->password))
193 {
194 /* prepare credential */
195 SmlCred *cred = smlCredNewAuth(dsObject->authType,
196 dsObject->username, dsObject->password,
197 &error);
198 if (!cred)
199 goto error;
200 smlSessionRegisterCred(dsObject->session, cred);
201 smlTrace(TRACE_INTERNAL, "%s: credential initialized", __func__);
202 }
203
204 break;
205 case SML_MANAGER_SESSION_FINAL:
206 smlTrace(TRACE_INTERNAL, "%s: Session %s reported final",
207 __func__, VA_STRING(smlSessionGetSessionID(session)));
208
209 /* determine which package was received */
210
211 if (dsObject->dsType == SML_SESSION_TYPE_CLIENT)
212 {
213 /* only devinf receiving is not supported */
214 if (dsObject->actualPackage < SML_PACKAGE_1)
215 dsObject->actualPackage = SML_PACKAGE_1;
216 else
217 dsObject->actualPackage += 2;
218 } else { // SML_SESSION_TYPE_SERVER
219 /* only devinf receiving is not supported */
220 if (dsObject->actualPackage < SML_PACKAGE_2)
221 dsObject->actualPackage = SML_PACKAGE_2;
222 else
223 dsObject->actualPackage += 2;
224 }
225 smlTrace(TRACE_INTERNAL, "%s: package == %d", __func__, dsObject->actualPackage);
226
227 /* start callbacks etc. according to state */
228
229 switch(dsObject->actualPackage)
230 {
231 case SML_PACKAGE_1: /* SAN received by client */
232 /* This is the best position to check for
233 * the availability of the remote device
234 * information. If it is not present then
235 * the own device information is send and
236 * the remote ones is requested.
237 */
238 if (!smlDataSyncManageDevInf(dsObject, TRUE, &error))
239 goto error;
240 if (!smlSessionFlush(dsObject->session, TRUE, &error))
241 goto error;
242 break;
243 case SML_PACKAGE_2: /* alerts received by server */
244 /* This is the best position to check for
245 * the availability of the remote device
246 * information. If it is not present then
247 * the own device information is send and
248 * the remote ones is requested.
249 */
250 if (!smlDataSyncManageDevInf(dsObject, TRUE, &error))
251 goto error;
252
253 if (!smlSessionFlush(dsObject->session, TRUE, &error))
254 goto error;
255
256 smlDataSyncSendEvent(
257 dsObject, SML_DATA_SYNC_EVENT_GOT_ALL_ALERTS,
258 dsObject->eventUserdata, NULL);
259 break;
260 case SML_PACKAGE_3: /* alerts received by client */
261 smlDataSyncSendEvent(
262 dsObject, SML_DATA_SYNC_EVENT_GOT_ALL_ALERTS,
263 dsObject->eventUserdata, NULL);
264 break;
265 case SML_PACKAGE_4: /* syncs received by server */
266 smlDataSyncSendEvent(
267 dsObject, SML_DATA_SYNC_EVENT_GOT_ALL_CHANGES,
268 dsObject->eventUserdata, NULL);
269 break;
270 case SML_PACKAGE_5: /* syncs received by client */
271 if (!smlDataSyncSendMap(dsObject, &error))
272 goto error;
273 if (!smlSessionFlush(dsObject->session, TRUE, &error))
274 goto error;
275 smlDataSyncSendEvent(
276 dsObject, SML_DATA_SYNC_EVENT_GOT_ALL_CHANGES,
277 dsObject->eventUserdata, NULL);
278 break;
279 case SML_PACKAGE_6: /* map received by server */
280 if (!smlSessionFlush(dsObject->session, TRUE, &error))
281 goto error;
282 break;
283 case SML_PACKAGE_END: /* end received by client */
284 /* everything done */
285 /* auto disconnect by library */
286 break;
287 default:
288 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED,
289 "The package %d is actually not supported.",
290 dsObject->actualPackage);
291 goto error;
292 }
293 break;
294 case SML_MANAGER_SESSION_END:
295 smlTrace(TRACE_INTERNAL, "%s: Session %s has ended",
296 __func__, VA_STRING(smlSessionGetSessionID(session)));
297 SmlLink *link_ = smlManagerSessionGetLink(
298 dsObject->manager,
299 dsObject->session,
300 &error);
301 if (!link_ && error)
302 goto error;
303 /* OBEX is a stateful protocol and the client should
304 * init the disconnect. The problem is what happens
305 * when the client hangs?
306 *
307 * if (dsObject->tspType != SML_TRANSPORT_OBEX_SERVER &&
308 * !smlTransportDisconnect(dsObject->tsp, link, &error))
309 */
310 if (!smlTransportDisconnect(dsObject->tsp, link_, &error))
311 {
312 if (link_)
313 smlLinkDeref(link_);
314 goto error;
315 }
316 if (link_)
317 smlLinkDeref(link_);
318 break;
319 case SML_MANAGER_SESSION_ERROR:
320 if (session)
321 smlTrace(TRACE_INTERNAL,
322 "There was an error in the session %s: %s",
323 VA_STRING(smlSessionGetSessionID(session)),
324 smlErrorPrint(&error));
325 else
326 smlTrace(TRACE_INTERNAL,
327 "There was a general error in the manager. %s",
328 smlErrorPrint(&error));
329
330 goto error;
331 break;
332 case SML_MANAGER_SESSION_WARNING:
333 g_warning("WARNING: %s\n", smlErrorPrint(&error));
334 break;
335 default:
336 g_warning("%s: Unknown event received: %d.", __func__, type);
337 break;
338 }
339
340 g_mutex_unlock(dsObject->managerMutex);
341 smlTrace(TRACE_EXIT, "%s", __func__);
342 return;
343
344 error:
345 g_mutex_unlock(dsObject->managerMutex);
346 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
347 smlDataSyncSendEvent(
348 dsObject, SML_DATA_SYNC_EVENT_ERROR,
349 dsObject->eventUserdata, error);
350 }
351
352 /* *************************************** */
353 /* ***** DsSession Callbacks ***** */
354 /* *************************************** */
355
356 void smlDataSyncDatastoreConnectCallback(
357 SmlDsSession *dsession,
358 void *userdata)
359 {
360 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, userdata);
361 smlAssert(dsession);
362 smlAssert(userdata);
363
364 SmlDataSyncDatastore *datastore = userdata;
365 SmlDataSyncObject *dsObject = datastore->dsObject;
366
367 /* The session is required here. So if the session is missing
368 * then the function has to block here. This is no real problem
369 * because the SESSION_EVENT_NEW must already be in the queue of
370 * the manager object.
371 */
372 while (!dsObject->session) {
373 smlManagerDispatch(dsObject->manager);
374 }
375
376 /* set callbacks if the DsSession was not ready before */
377 if (!datastore->session || datastore->session != dsession)
378 {
379 smlTrace(TRACE_INTERNAL, "%s: should be an OMA DS server", __func__);
380 smlAssert(dsObject->funcDatastoreAlert);
381 datastore->session = dsession;
382 smlDsSessionGetAlert(datastore->session, dsObject->funcDatastoreAlert, datastore);
383 if (dsObject->changeCallback) {
384 smlDsSessionGetSync(datastore->session,
385 smlDataSyncSyncCallback, datastore);
386 smlDsSessionGetChanges(datastore->session,
387 smlDataSyncChangeCallback, datastore);
388 smlDsSessionGetMapping(datastore->session,
389 smlDataSyncMappingCallback, datastore);
390 }
391 smlDsSessionRef(dsession);
392 }
393
394 smlTrace(TRACE_EXIT, "%s", __func__);
395 return;
396
397 #if 0 /* UNUSED */
398 error:
399 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
400 smlDataSyncSendEvent(
401 dsObject, SML_DATA_SYNC_EVENT_ERROR,
402 dsObject->eventUserdata, error);
403 #endif /* UNUSED */
404 }
405
406
407 /* *********************************** */
408 /* ***** Alert Callbacks ***** */
409 /* *********************************** */
410
411 void smlDataSyncAlertStatusCallback(
412 SmlSession *session,
413 SmlStatus *status,
414 void *userdata)
415 {
416 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
417
418 SmlDataSyncDatastore *datastore = userdata;
419
420 /* If we talk as an OMA DS client with server like an OCS
421 * then it can happen that this server denies the alert
422 * because of an internal problem.
423 * Example OCS: If there is an error inside of an SyncML session
424 * then you must wait a configured time before you
425 * can again sucessfully connect this server.
426 * Typically the server responds with error 503.
427 */
428 unsigned int code = smlStatusGetCode(status);
429 if (code >= 300 && code != SML_ERROR_REQUIRE_REFRESH)
430 {
431 /* This is an error. */
432 SmlError *error = NULL;
433 smlErrorSet(&error, SML_ERROR_GENERIC,
434 "The alert response signals an error - %d.", code);
435 smlErrorRef(&error);
436 smlDataSyncSendEvent(
437 datastore->dsObject, SML_DATA_SYNC_EVENT_ERROR,
438 datastore->dsObject->eventUserdata, error);
439 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
440 smlErrorDeref(&error);
441 } else {
442 smlTrace(TRACE_EXIT, "%s", __func__);
443 }
444 }
445
446 /* ********************************** */
447 /* ***** Sync Callbacks ***** */
448 /* ********************************** */
449
450 void smlDataSyncSyncCallback(
451 SmlDsSession *dsession,
452 unsigned int numchanges,
453 void *userdata)
454 {
455 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, dsession, numchanges, userdata);
456 SmlDataSyncDatastore *datastore = userdata;
457 SmlError *error = NULL;
458
459 /* If the device information was not sent together with the
460 * alerts and it was not cached then the device information
461 * can be received together with the sync command(s).
462 * This can happen with OMA DS clients and servers.
463 */
464 if (!smlDataSyncManageDevInf(datastore->dsObject, FALSE, &error))
465 goto error;
466
467 smlTrace(TRACE_EXIT, "%s", __func__);
468 return;
469 error:
470 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
471 smlDataSyncSendEvent(
472 datastore->dsObject, SML_DATA_SYNC_EVENT_ERROR,
473 datastore->dsObject->eventUserdata, error);
474 }
475
476 void smlDataSyncSyncStatusCallback(
477 SmlSession *session,
478 SmlStatus *status,
479 void *userdata)
480 {
481 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, session, status, userdata);
482 SmlDataSyncDatastore *datastore = userdata;
483
484 if (smlStatusGetClass(status) != SML_ERRORCLASS_SUCCESS)
485 {
486 // inform user
487 smlTrace(TRACE_INTERNAL, "%s: The synchronisation request failed.", __func__);
488 smlTrace(TRACE_INTERNAL, "%s: Location => %s", __func__, VA_STRING(datastore->dsObject->url));
489 smlTrace(TRACE_INTERNAL, "%s: Database => %s", __func__, VA_STRING(datastore->sourceUri));
490 smlTrace(TRACE_INTERNAL, "%s: Error => %d", __func__, smlStatusGetCode(status));
491 if (smlStatusGetCode(status) == SML_ERROR_SERVICE_UNAVAILABLE &&
492 (strstr(datastore->dsObject->url, "ocst") ||
493 strstr(datastore->dsObject->url, "ocas")))
494 {
495 /* this is a potential Oracle Collaboration Suite */
496 /* typical errorcode from OCS if there is something wrong */
497 smlTrace(TRACE_INTERNAL,
498 "%s: Oracle Collaboration Suite detected.",
499 __func__);
500 smlTrace(TRACE_INTERNAL,
501 "%s: Typical undefined error from OCS (503 - SyncML timeout error).",
502 __func__);
503 smlTrace(TRACE_INTERNAL,
504 "%s: Please wait 5 minutes before retry - default session timeout.",
505 __func__);
506 }
507 // stop session
508 // FIXME: this is not available in a clean way today
509 // FIXME: we need a session state
510 // FIXME: osync must be signalled
511 // FIXME: we need a mutex lock on database->env
512 // smlSessionEnd(database->env->session, NULL);
513 // printf(" Session finished.\n");
514 // smlManagerSessionRemove(database->env->manager, database->env->session);
515 // smlManagerStop(database->env->manager);
516 // smlManagerQuit(database->env->manager);
517 // printf(" Manager finished.\n");
518 SmlError *error = NULL;
519 smlErrorSet(&error, smlStatusGetCode(status),
520 "Sync failed with error %d.",
521 smlStatusGetCode(status));
522 smlErrorRef(&error);
523 smlDataSyncSendEvent(
524 datastore->dsObject, SML_DATA_SYNC_EVENT_ERROR,
525 datastore->dsObject->eventUserdata, error);
526 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
527 smlErrorDeref(&error);
528 } else {
529 smlTrace(TRACE_EXIT, "%s", __func__);
530 }
531 }
532
533 /* ************************************ */
534 /* ***** Change Callbacks ***** */
535 /* ************************************ */
536
537 SmlBool smlDataSyncChangeCallback(
538 SmlDsSession *dsession,
539 SmlChangeType type,
540 const char *uid,
541 char *data,
542 unsigned int size,
543 const char *contenttype,
544 void *userdata,
545 SmlError **error)
546 {
547 smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %p, %i, %s, %p, %p)", __func__, dsession, type, VA_STRING(uid), data, size, VA_STRING(contenttype), userdata, error);
548 CHECK_ERROR_REF
549
550 SmlDataSyncDatastore *datastore = userdata;
551
552 smlAssert(type);
553 smlAssert(datastore);
554 smlAssert(datastore->dsObject);
555 smlAssert(datastore->dsObject->changeCallback);
556
557 /* some mobiles sends replace commands during slow-sync */
558 if (datastore->alertType == SML_ALERT_SLOW_SYNC &&
559 type == SML_CHANGE_REPLACE)
560 type = SML_CHANGE_ADD;
561
562 /* decode base64 data if necessary */
563 size_t appClassLength = ((size_t) index(datastore->contentType, '/')) -
564 ((size_t) datastore->contentType);
565 if ( ( strstr(datastore->contentType, SML_CONTENT_TYPE_APPLICATION) == datastore->contentType &&
566 appClassLength == strlen(SML_CONTENT_TYPE_APPLICATION) ) ||
567 ( strstr(datastore->contentType, SML_CONTENT_TYPE_AUDIO) == datastore->contentType &&
568 appClassLength == strlen(SML_CONTENT_TYPE_AUDIO) ) ||
569 ( strstr(datastore->contentType, SML_CONTENT_TYPE_IMAGE) == datastore->contentType &&
570 appClassLength == strlen(SML_CONTENT_TYPE_IMAGE) ) ||
571 ( strstr(datastore->contentType, SML_CONTENT_TYPE_MESSAGE) == datastore->contentType &&
572 appClassLength == strlen(SML_CONTENT_TYPE_MESSAGE) ) ||
573 ( strstr(datastore->contentType, SML_CONTENT_TYPE_VIDEO) == datastore->contentType &&
574 appClassLength == strlen(SML_CONTENT_TYPE_AUDIO) ) )
575 {
576 /* binary data must be base64 encoded */
577 char *b64data = data;
578 size_t length = 0;
579 data = (char *) g_base64_decode(b64data, &length);
580 size = length;
581 smlSafeCFree(&b64data);
582 if (!data) {
583 smlErrorSet(error, SML_ERROR_GENERIC,
584 "The base 64 decoding of glib failed.");
585 goto error;
586 }
587 }
588
589 /* perform callback */
590 if (!datastore->dsObject->changeCallback(
591 datastore->dsObject, datastore->sourceUri,
592 type, uid, data, size,
593 datastore->dsObject->changeUserdata,
594 error))
595 goto error;
596
597 /* if this is a client then the callback should add a mapping */
598
599 smlTrace(TRACE_EXIT, "%s", __func__);
600 return TRUE;
601 error:
602 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
603 return FALSE;
604 }
605
606 void smlDataSyncChangeStatusCallback(
607 SmlDsSession *dsession,
608 SmlStatus *status,
609 const char *newuid,
610 void *userdata)
611 {
612 smlTrace(TRACE_ENTRY, "%s(%p, %p, %s, %p)", __func__, dsession, status, VA_STRING(newuid), userdata);
613 SmlError *error = NULL;
614
615 smlAssert(userdata);
616 SmlDataSyncChange *change = userdata;
617 SmlDataSyncDatastore *datastore = change->datastore;
618 SmlDataSyncObject *dsObject = datastore->dsObject;
619
620 smlAssert(dsObject);
621 if (dsObject->changeStatusCallback &&
622 !dsObject->changeStatusCallback(
623 dsObject,
624 smlStatusGetCode(status),
625 newuid,
626 change->userdata, &error))
627 goto error;
628
629 smlTrace(TRACE_EXIT, "%s", __func__);
630 return;
631 error:
632 smlErrorRef(&error);
633 smlDataSyncSendEvent(
634 dsObject, SML_DATA_SYNC_EVENT_ERROR,
635 dsObject->eventUserdata, error);
636 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
637 smlErrorDeref(&error);
638 }
639
640 void smlDataSyncMappingCallback(
641 SmlDsSession *dsession,
642 SmlLocation *orig,
643 SmlLocation *newuid,
644 void *userdata)
645 {
646 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, dsession, VA_STRING(smlLocationGetURI(orig)), VA_STRING(smlLocationGetURI(newuid)), userdata);
647
648 SmlError *error = NULL;
649 SmlDataSyncDatastore *datastore = userdata;
650
651 smlAssert(datastore);
652 smlAssert(datastore->dsObject);
653 smlAssert(datastore->dsObject->mappingCallback);
654
655 /* perform callback */
656 if (!datastore->dsObject->mappingCallback(
657 datastore->dsObject, datastore->sourceUri,
658 smlLocationGetURI(orig),
659 smlLocationGetURI(newuid),
660 datastore->dsObject->mappingUserdata,
661 &error))
662 goto error;
663
664 smlTrace(TRACE_EXIT, "%s", __func__);
665 return;
666 error:
667 smlErrorRef(&error);
668 smlDataSyncSendEvent(
669 datastore->dsObject, SML_DATA_SYNC_EVENT_ERROR,
670 datastore->dsObject->eventUserdata, error);
671 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
672 smlErrorDeref(&error);
673 }
674
675 /* ********************************* */
676 /* ***** Map Callbacks ***** */
677 /* ********************************* */
678
679 void smlDataSyncMapStatusCallback(
680 SmlSession *session,
681 SmlStatus *status,
682 void *userdata)
683 {
684 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
685 if (smlStatusGetClass(status) != SML_ERRORCLASS_SUCCESS)
686 {
687 SmlDataSyncDatastore *datastore = userdata;
688 SmlError *error = NULL;
689 smlErrorSet(&error, smlStatusGetCode(status),
690 "Map of datastore %s was rejected with error code %d",
691 datastore->sourceUri, smlStatusGetCode(status));
692 smlDataSyncSendEvent(
693 datastore->dsObject, SML_DATA_SYNC_EVENT_ERROR,
694 datastore->dsObject->eventUserdata, error);
695 }
696 smlTrace(TRACE_EXIT, "%s", __func__);
697 }
698
699 /* ******************************************* */
700 /* ***** Authentication Callback ***** */
701 /* ******************************************* */
702
703 SmlBool smlDataSyncVerifyUserCallback(
704 SmlChal *chal,
705 SmlCred *cred,
706 const char *username,
707 void *userdata,
708 SmlError **error)
709 {
710 smlTrace(TRACE_ENTRY, "%s(%p, %p, %s, %p)", __func__, chal, cred, VA_STRING(username), userdata);
711 CHECK_ERROR_REF
712
713 SmlDataSyncObject *dsObject = userdata;
714
715 /* We have only one user and not a whole user database. */
716 smlTrace(TRACE_EXIT, "%s", __func__);
717 return smlAuthVerify(chal, cred, dsObject->username, dsObject->password, error);
718 }
719