libsyncml  0.5.4
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 
void smlDsSessionGetChanges(SmlDsSession *dsession, SmlDsSessionChangesCb chgCallback, void *userdata)
Gets a already received sync command.
This object represents an OMA DS datastore.
Definition: data_sync.h:93
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
Definition: sml_error.c:299
This is the central synchronization object.
Definition: data_sync.h:110
SmlBool smlSessionFlush(SmlSession *session, SmlBool final, SmlError **error)
Flushes a session.
Definition: sml_session.c:2010
void smlDsSessionGetAlert(SmlDsSession *dsession, SmlDsSessionAlertCb callback, void *userdata)
Gets a already received alert.
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
Definition: sml_support.c:120
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.
Definition: sml_error.c:355
This internal structure represents exactly one change.
Definition: data_sync.h:207
Represent an error.