libsyncml  0.5.4
data_sync.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 "../syncml.h"
22 #include "../syncml_internals.h"
23 #include "../sml_error_internals.h"
24 
25 #include <libsyncml/data_sync_api/defines.h>
26 #include <libsyncml/data_sync_api/standard.h>
27 #include <libsyncml/data_sync_api/callbacks.h>
28 
29 /* required because of function index */
30 #include <strings.h>
31 
32 #include "data_sync.h"
33 #include "data_sync_client.h"
34 #include "data_sync_server.h"
35 #include "data_sync_callbacks.h"
36 #include "data_sync_callbacks.h"
37 #include "data_sync_devinf.h"
38 #include "data_sync_loop.h"
39 #include "transport.h"
40 #include "libsyncml/objects/sml_ds_server_internals.h"
41 
42 /* ********************************* */
43 /* object creation and configuration */
44 /* ********************************* */
45 
46 SmlDataSyncObject *smlDataSyncNew(
47  SmlSessionType dsType,
48  SmlTransportType tspType,
49  SmlError **error)
50 {
51  smlTrace(TRACE_ENTRY, "%s(%d, %d, %p)", __func__, dsType, tspType, error);
52  CHECK_ERROR_REF
53 
54  smlTrace(TRACE_INTERNAL, "%s: libsyncml version: %s", __func__, VERSION);
55 
56  SmlDataSyncObject *dsObject = smlTryMalloc0(sizeof(SmlDataSyncObject), error);
57  if (!dsObject)
58  goto error;
59  smlDataSyncObjectRef(dsObject);
60 
61  dsObject->dsType = dsType;
62  dsObject->tspType = tspType;
63  dsObject->version = SML_VERSION_11;
64  dsObject->internalState = SML_DATA_SYNC_STATE_NEW;
65 
66  dsObject->useNumberOfChanges = TRUE;
67  dsObject->useTimestampAnchor = TRUE;
68  dsObject->maxObjSize = SML_DEFAULT_MAX_OBJ_SIZE;
69  dsObject->maxMsgSize = SML_DEFAULT_MAX_MSG_SIZE;
70 
71  dsObject->tsp = smlTransportNew(tspType, error);
72  if (!dsObject->tsp)
73  goto error;
74  switch(tspType)
75  {
76  case SML_TRANSPORT_OBEX_CLIENT:
77  dsObject->funcTspInit = smlDataSyncTransportObexClientInit;
78  dsObject->funcTspConnect = smlDataSyncTransportObexClientConnect;
79  break;
80  case SML_TRANSPORT_OBEX_SERVER:
81  dsObject->funcTspInit = NULL;
82  dsObject->funcTspConnect = NULL;
83  break;
84  case SML_TRANSPORT_HTTP_SERVER:
85  dsObject->funcTspInit = smlDataSyncTransportHttpServerInit;
86  dsObject->funcTspConnect = NULL;
87  break;
88  case SML_TRANSPORT_HTTP_CLIENT:
89  dsObject->funcTspInit = smlDataSyncTransportHttpClientInit;
90  dsObject->funcTspConnect = smlDataSyncTransportHttpClientConnect;
91  break;
92  default:
93  smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
94  "Unknown transport type %d used in __func__.",
95  tspType, __func__);
96  goto error;
97  break;
98  }
99  switch(dsType)
100  {
101  case SML_SESSION_TYPE_SERVER:
102  dsObject->funcDsInit = smlDataSyncServerInit;
103  dsObject->funcDsConnect = NULL;
104  break;
105  case SML_SESSION_TYPE_CLIENT:
106  dsObject->funcDsInit = smlDataSyncClientInit;
107  dsObject->funcDsConnect = NULL;
108  break;
109  default:
110  smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
111  "Unknown data sync type %d used in %s.",
112  dsType, __func__);
113  goto error;
114  break;
115  }
116 
117  smlTrace(TRACE_EXIT, "%s - %p", __func__, dsObject);
118  return dsObject;
119 error:
120  if (dsObject) {
121  if (dsObject->tsp)
122  smlTransportFree(dsObject->tsp);
123  smlDataSyncObjectUnref(&dsObject);
124  }
125  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
126  return NULL;
127 }
128 
129 void smlDataSyncObjectRef(SmlDataSyncObject *dsObject)
130 {
131  g_atomic_int_inc(&(dsObject->refCount));
132 }
133 
134 SmlBool smlDataSyncSetOption(
135  SmlDataSyncObject *dsObject,
136  const char *name,
137  const char *value,
138  SmlError **error)
139 {
140  smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, dsObject, VA_STRING(name), VA_STRING(value), error);
141  CHECK_ERROR_REF
142 
143  if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_TYPE, name)) {
144  if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_SERIAL, value))
145  dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_SERIAL;
146  if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_BLUETOOTH, value))
147  dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH;
148  if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_IRDA, value))
149  dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_IRDA;
150  if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_NET, value))
151  dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_NET;
152  if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_USB, value))
153  dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_USB;
154  if (!smlTransportSetConnectionType(dsObject->tsp, dsObject->conType, error))
155  goto error;
156  } else if (!strcmp(SML_DATA_SYNC_CONFIG_VERSION, name)) {
157  dsObject->version = SML_VERSION_UNKNOWN;
158  if (!strcmp("1.0", value))
159  dsObject->version = SML_VERSION_10;
160  if (!strcmp("1.1", value))
161  dsObject->version = SML_VERSION_11;
162  if (!strcmp("1.2", value))
163  dsObject->version = SML_VERSION_12;
164  if (dsObject->version == SML_VERSION_UNKNOWN) {
165  smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
166  "Unknown SyncML version %s.", value);
167  goto error;
168  }
169  } else if (!strcmp(SML_DATA_SYNC_CONFIG_AUTH_TYPE, name)) {
170  if (!strcmp(value, SML_DATA_SYNC_CONFIG_AUTH_BASIC)) {
171  dsObject->authType = SML_AUTH_TYPE_BASIC;
172  } else if (!strcmp(value, SML_DATA_SYNC_CONFIG_AUTH_MD5)) {
173  dsObject->authType = SML_AUTH_TYPE_MD5;
174  } else if (!strcmp(value, SML_DATA_SYNC_CONFIG_AUTH_NONE)) {
175  dsObject->authType = SML_AUTH_TYPE_UNKNOWN;
176  } else {
177  // this is an illegal keyword
178  smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
179  "Unknown authentication type %s.", value);
180  goto error;
181  }
182  } else if (!strcmp(SML_TRANSPORT_CONFIG_URL, name)) {
183  dsObject->url = g_strdup(value);
184  /* If the Target is not set explicitly
185  * then the URL is used as the Target in the session header.
186  * This is only relevant for HTTP clients today.
187  */
188  if (!dsObject->target)
189  dsObject->target = g_strdup(value);
190  } else if (!strcmp(SML_DATA_SYNC_CONFIG_TARGET, name)) {
191  if (dsObject->target)
192  smlSafeCFree(&(dsObject->target));
193  dsObject->target = g_strdup(value);
194  } else if (!strcmp(SML_DATA_SYNC_CONFIG_IDENTIFIER, name)) {
195  if (dsObject->identifier)
196  smlSafeCFree(&(dsObject->identifier));
197  if (value && strlen(value)) {
198  dsObject->identifier = g_strdup(value);
199  } else {
200  smlTrace(TRACE_INTERNAL,
201  "%s: set identifier to NULL", __func__);
202  }
203  } else if (!strcmp(SML_DATA_SYNC_CONFIG_AUTH_USERNAME, name)) {
204  dsObject->username = g_strdup(value);
205  } else if (!strcmp(SML_DATA_SYNC_CONFIG_AUTH_PASSWORD, name)) {
206  dsObject->password = g_strdup(value);
207  } else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_WBXML, name)) {
208  dsObject->useWbxml = atoi(value);
209  } else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_STRING_TABLE, name)) {
210  dsObject->useStringTable = atoi(value);
211  } else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_TIMESTAMP_ANCHOR, name)) {
212  dsObject->useTimestampAnchor = atoi(value);
213  } else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_NUMBER_OF_CHANGES, name)) {
214  dsObject->useNumberOfChanges = atoi(value);
215  } else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_LOCALTIME, name)) {
216  dsObject->onlyLocaltime = atoi(value);
217  } else if (!strcmp(SML_DATA_SYNC_CONFIG_ONLY_REPLACE, name)) {
218  dsObject->onlyReplace = atoi(value);
219  } else if (!strcmp(SML_DATA_SYNC_CONFIG_MAX_OBJ_SIZE, name)) {
220  dsObject->maxObjSize = atoi(value);
221  } else if (!strcmp(SML_DATA_SYNC_CONFIG_MAX_MSG_SIZE, name)) {
222  dsObject->maxMsgSize = atoi(value);
223  } else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_DEVICE, name)) {
224  dsObject->fakeDevice = g_strdup(value);
225  } else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_MANUFACTURER, name)) {
226  dsObject->fakeManufacturer = g_strdup(value);
227  } else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_MODEL, name)) {
228  dsObject->fakeModel = g_strdup(value);
229  } else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_SOFTWARE_VERSION, name)) {
230  dsObject->fakeSoftwareVersion = g_strdup(value);
231  } else {
232  if (!smlTransportSetConfigOption(dsObject->tsp, name, value, error))
233  goto error;
234  }
235 
236  // the default is syncml:auth-basic
237  if ((dsObject->username || dsObject->password) &&
238  dsObject->authType == SML_AUTH_TYPE_UNKNOWN)
239  {
240  smlTrace(TRACE_INTERNAL,
241  "%s: authType is set to default (syncml:auth-basic)", __func__);
242  dsObject->authType = SML_AUTH_TYPE_BASIC;
243  }
244 
245  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
246  return TRUE;
247 error:
248  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
249  return FALSE;
250 }
251 
252 SmlBool smlDataSyncAddDatastore(SmlDataSyncObject *dsObject,
253  const char *contentType,
254  const char *target,
255  const char *source,
256  SmlError **error)
257 {
258  smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %s, %p)", __func__, dsObject, VA_STRING(contentType), VA_STRING(target), VA_STRING(source), error);
259  CHECK_ERROR_REF
260 
261  char *lcCT = NULL;
262  char *lcSource = NULL;
263 
264  SmlDataSyncDatastore *datastore = smlTryMalloc0(sizeof(SmlDataSyncDatastore), error);
265  if (!datastore)
266  goto error;
267 
268  datastore->dsObject = dsObject;
269  datastore->syncChanges = NULL;
270  datastore->syncContexts = NULL;
271  datastore->sourceUri = g_strdup(source);
272  datastore->targetUri = g_strdup(target);
273  datastore->contentType = g_strdup(contentType);
274 
275  dsObject->datastores = g_list_append(dsObject->datastores, datastore);
276 
277  /* especially Samsung devices need the datastores during connect */
278 
279  if (dsObject->tspType == SML_TRANSPORT_OBEX_CLIENT)
280  {
281  lcCT = g_ascii_strdown(contentType, strlen(contentType));
282  lcSource = g_utf8_strdown(source, strlen(source));
283  if (strstr(lcCT, "vcard") &&
285  dsObject->tsp,
286  SML_TRANSPORT_CONFIG_DATASTORE,
287  SML_TRANSPORT_CONFIG_DATASTORE_CONTACT,
288  error))
289  {
290  goto error;
291  }
292  if (strstr(lcCT, "calendar") &&
293  ( strstr(lcSource, "cal") ||
294  strstr(lcSource, "event")
295  )&&
297  dsObject->tsp,
298  SML_TRANSPORT_CONFIG_DATASTORE,
299  SML_TRANSPORT_CONFIG_DATASTORE_EVENT,
300  error))
301  {
302  goto error;
303  }
304  if (strstr(lcCT, "calendar") &&
305  strstr(lcSource, "todo") &&
307  dsObject->tsp,
308  SML_TRANSPORT_CONFIG_DATASTORE,
309  SML_TRANSPORT_CONFIG_DATASTORE_TODO,
310  error))
311  {
312  goto error;
313  }
314  if (strstr(lcCT, "text/plain") &&
316  dsObject->tsp,
317  SML_TRANSPORT_CONFIG_DATASTORE,
318  SML_TRANSPORT_CONFIG_DATASTORE_NOTE,
319  error))
320  {
321  goto error;
322  }
323  smlSafeCFree(&lcCT);
324  smlSafeCFree(&lcSource);
325  }
326 
327  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
328  return TRUE;
329 error:
330  if (datastore)
331  smlSafeFree((gpointer *)&datastore);
332  if (lcCT)
333  smlSafeCFree(&lcCT);
334  if (lcSource)
335  smlSafeCFree(&lcSource);
336  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
337  return FALSE;
338 }
339 
340 static SmlDataSyncDatastore *smlDataSyncGetDatastoreFromSource(
341  SmlDataSyncObject *dsObject,
342  const char *source,
343  SmlError **error)
344 {
345  CHECK_ERROR_REF
346  smlAssert(dsObject);
347  smlAssert(source);
348 
349  GList *o = dsObject->datastores;
350  for (; o; o = o->next) {
351  SmlDataSyncDatastore *datastore = o->data;
352  if (!strcmp(datastore->sourceUri, source))
353  return datastore;
354  }
355 
356  smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
357  "Cannot find datastore for source name %s.", source);
358  return NULL;
359 }
360 
361 /* ***************************** */
362 /* register callbacks */
363 /* ***************************** */
364 
365 void smlDataSyncRegisterEventCallback(
366  SmlDataSyncObject *dsObject,
367  SmlDataSyncEventCallback callback,
368  void *userdata)
369 {
370  smlTrace(TRACE_ENTRY, "%s", __func__);
371  smlAssert(dsObject);
372  smlAssert(callback);
373 
374  dsObject->eventCallback = callback;
375  dsObject->eventUserdata = userdata;
376 
377  smlTrace(TRACE_EXIT, "%s", __func__);
378 }
379 
380 void smlDataSyncRegisterGetAlertTypeCallback(
381  SmlDataSyncObject *dsObject,
382  SmlDataSyncGetAlertTypeCallback callback,
383  void *userdata)
384 {
385  smlTrace(TRACE_ENTRY, "%s", __func__);
386  smlAssert(dsObject);
387  smlAssert(callback);
388 
389  dsObject->getAlertTypeCallback = callback;
390  dsObject->getAlertTypeUserdata = userdata;
391 
392  smlTrace(TRACE_EXIT, "%s", __func__);
393 }
394 
395 void smlDataSyncRegisterChangeCallback(
396  SmlDataSyncObject *dsObject,
397  SmlDataSyncChangeCallback callback,
398  void *userdata)
399 {
400  smlTrace(TRACE_ENTRY, "%s", __func__);
401  smlAssert(dsObject);
402  smlAssert(callback);
403 
404  dsObject->changeCallback = callback;
405  dsObject->changeUserdata = userdata;
406 
407  GList *o = dsObject->datastores;
408  for (;o;o = o->next) {
409  SmlDataSyncDatastore *datastore = o->data;
410  if (datastore->session) {
411  smlDsSessionGetSync(datastore->session,
412  smlDataSyncSyncCallback, datastore);
413  smlDsSessionGetChanges(datastore->session,
414  smlDataSyncChangeCallback, datastore);
415  }
416  }
417 
418  smlTrace(TRACE_EXIT, "%s", __func__);
419 }
420 
421 void smlDataSyncRegisterChangeStatusCallback(
422  SmlDataSyncObject *dsObject,
423  SmlDataSyncChangeStatusCallback callback)
424 {
425  smlTrace(TRACE_ENTRY, "%s", __func__);
426  smlAssert(dsObject);
427  smlAssert(callback);
428 
429  dsObject->changeStatusCallback = callback;
430  /* the userdata is set by the AddChange function */
431 
432  smlTrace(TRACE_EXIT, "%s", __func__);
433 }
434 
435 void smlDataSyncRegisterMapCallback(
436  SmlDataSyncObject *dsObject,
437  SmlDataSyncMappingCallback callback,
438  void *userdata)
439 {
440  smlTrace(TRACE_ENTRY, "%s", __func__);
441  smlAssert(dsObject);
442  smlAssert(callback);
443 
444  dsObject->mappingCallback = callback;
445  dsObject->mappingUserdata = userdata;
446 
447  GList *o = dsObject->datastores;
448  for (;o;o = o->next) {
449  SmlDataSyncDatastore *datastore = o->data;
450  if (datastore->session) {
451  smlDsSessionGetMapping(datastore->session,
452  smlDataSyncMappingCallback, datastore);
453  }
454  }
455 
456  smlTrace(TRACE_EXIT, "%s", __func__);
457 }
458 
459 
460 void smlDataSyncRegisterGetAnchorCallback(
461  SmlDataSyncObject *dsObject,
462  SmlDataSyncGetAnchorCallback callback,
463  void *userdata)
464 {
465  smlTrace(TRACE_ENTRY, "%s", __func__);
466  smlAssert(dsObject);
467  smlAssert(callback);
468 
469  dsObject->getAnchorCallback = callback;
470  dsObject->getAnchorUserdata = userdata;
471 
472  smlTrace(TRACE_EXIT, "%s", __func__);
473 }
474 
475 void smlDataSyncRegisterSetAnchorCallback(
476  SmlDataSyncObject *dsObject,
477  SmlDataSyncSetAnchorCallback callback,
478  void *userdata)
479 {
480  smlTrace(TRACE_ENTRY, "%s", __func__);
481  smlAssert(dsObject);
482  smlAssert(callback);
483 
484  dsObject->setAnchorCallback = callback;
485  dsObject->setAnchorUserdata = userdata;
486 
487  smlTrace(TRACE_EXIT, "%s", __func__);
488 }
489 
490 void smlDataSyncRegisterWriteDevInfCallback(
491  SmlDataSyncObject *dsObject,
492  SmlDataSyncWriteDevInfCallback callback,
493  void *userdata)
494 {
495  smlTrace(TRACE_ENTRY, "%s", __func__);
496  smlAssert(dsObject);
497  smlAssert(callback);
498 
499  dsObject->writeDevInfCallback = callback;
500  dsObject->writeDevInfUserdata = userdata;
501 
502  smlTrace(TRACE_EXIT, "%s", __func__);
503 }
504 
505 void smlDataSyncRegisterReadDevInfCallback(
506  SmlDataSyncObject *dsObject,
507  SmlDataSyncReadDevInfCallback callback,
508  void *userdata)
509 {
510  smlTrace(TRACE_ENTRY, "%s", __func__);
511  smlAssert(dsObject);
512  smlAssert(callback);
513 
514  dsObject->readDevInfCallback = callback;
515  dsObject->readDevInfUserdata = userdata;
516 
517  smlTrace(TRACE_EXIT, "%s", __func__);
518 }
519 
520 void smlDataSyncRegisterHandleRemoteDevInfCallback(
521  SmlDataSyncObject *dsObject,
522  SmlDataSyncHandleRemoteDevInfCallback callback,
523  void *userdata)
524 {
525  smlTrace(TRACE_ENTRY, "%s", __func__);
526  smlAssert(dsObject);
527  smlAssert(callback);
528 
529  dsObject->handleRemoteDevInfCallback = callback;
530  dsObject->handleRemoteDevInfUserdata = userdata;
531 
532  smlTrace(TRACE_EXIT, "%s", __func__);
533 }
534 
535 /* ***************************** */
536 /* init session */
537 /* ***************************** */
538 
539 SmlBool smlDataSyncInit(SmlDataSyncObject *dsObject, SmlError **error)
540 {
541  smlTrace(TRACE_ENTRY, "%s", __func__);
542  CHECK_ERROR_REF
543  smlAssert(dsObject);
544 
545  if (!dsObject->identifier)
546  dsObject->identifier = smlDataSyncDevInfGetIdentifier();
547 
548  dsObject->managerMutex = g_mutex_new();
549 
550  if (dsObject->funcTspInit &&
551  !dsObject->funcTspInit(dsObject, error))
552  goto error;
553  if (!dsObject->funcDsInit(dsObject, error))
554  goto error;
555 
556  dsObject->internalState = SML_DATA_SYNC_STATE_INITIALIZED;
557 
558  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
559  return TRUE;
560 error:
561  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
562  return FALSE;
563 }
564 
565 SmlBool smlDataSyncRun(SmlDataSyncObject *dsObject, SmlError **error)
566 {
567  smlTrace(TRACE_ENTRY, "%s", __func__);
568  CHECK_ERROR_REF
569 
570  /* If a server was initialized then you cannot do more
571  * than waiting for the remote client.
572  */
573 
574  if (dsObject->funcTspConnect &&
575  !dsObject->funcTspConnect(dsObject, error))
576  goto error;
577  if (dsObject->funcDsConnect &&
578  !dsObject->funcDsConnect(dsObject, error))
579  goto error;
580 
581  if (!smlDataSyncLoopStart(dsObject, error))
582  goto error;
583 
584  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
585  return TRUE;
586 error:
587  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
588  return FALSE;
589 }
590 
591 /* synchronize */
592 
593 SmlBool smlDataSyncAddChange(
594  SmlDataSyncObject *dsObject,
595  const char *source,
596  SmlChangeType type,
597  const char *name,
598  const char *data,
599  unsigned int size,
600  void *userdata, /* for SmlDataSyncChangeStatusCallback */
601  SmlError **error)
602 {
603  smlTrace(TRACE_ENTRY, "%s(%s)", __func__, VA_STRING(source));
604 
605  /* check params */
606  CHECK_ERROR_REF
607  smlAssert(dsObject);
608  smlAssert(source);
609  smlAssert(type);
610 
611  /* create a new change */
612  SmlDataSyncChange *change = smlTryMalloc0(sizeof(SmlDataSyncChange), error);
613  if (!change)
614  goto error;
615 
616  /* fill the new change */
617  change->type = type;
618  change->name = g_strdup(name);
619  change->userdata = userdata;
620 
621  /* determine the datastore */
622  change->datastore = smlDataSyncGetDatastoreFromSource(dsObject, source, error);
623  if (!change->datastore)
624  goto error;
625  SmlDataSyncDatastore *datastore = change->datastore;
626 
627  /* copy data */
628  if (data) {
629  smlAssert(datastore->contentType);
630  smlAssert(index(datastore->contentType, '/'));
631  size_t appClassLength = ((size_t) index(datastore->contentType, '/')) -
632  ((size_t) datastore->contentType);
633  if ( ( strstr(datastore->contentType, SML_CONTENT_TYPE_APPLICATION) == datastore->contentType &&
634  appClassLength == strlen(SML_CONTENT_TYPE_APPLICATION) ) ||
635  ( strstr(datastore->contentType, SML_CONTENT_TYPE_AUDIO) == datastore->contentType &&
636  appClassLength == strlen(SML_CONTENT_TYPE_AUDIO) ) ||
637  ( strstr(datastore->contentType, SML_CONTENT_TYPE_IMAGE) == datastore->contentType &&
638  appClassLength == strlen(SML_CONTENT_TYPE_IMAGE) ) ||
639  ( strstr(datastore->contentType, SML_CONTENT_TYPE_MESSAGE) == datastore->contentType &&
640  appClassLength == strlen(SML_CONTENT_TYPE_MESSAGE) ) ||
641  ( strstr(datastore->contentType, SML_CONTENT_TYPE_VIDEO) == datastore->contentType &&
642  appClassLength == strlen(SML_CONTENT_TYPE_AUDIO) ) )
643  {
644  /* binary data must be base64 encoded */
645  change->data = g_base64_encode((const unsigned char *) data, size);
646  if (!change->data) {
647  smlErrorSet(error, SML_ERROR_GENERIC,
648  "The base 64 encoding of glib failed.");
649  goto error;
650  }
651  change->size = strlen(change->data);
652  } else {
653  change->data = smlTryMalloc0(size+1, error);
654  if (!change->data)
655  goto error;
656  memcpy(change->data, data, size);
657  change->size = size;
658  }
659  } else {
660  change->data = NULL;
661  change->size = 0;
662  }
663 
664  /* append change to datastore */
665  datastore->changes = g_list_append(datastore->changes, change);
666 
667  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
668  return TRUE;
669 error:
670  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
671  return FALSE;
672 }
673 
674 SmlBool smlDataSyncSendChanges(SmlDataSyncObject *dsObject, SmlError **error)
675 {
676  /* This means that all alerts were received
677  * and all changes were added.
678  * So let us flush the session. */
679  smlTrace(TRACE_ENTRY, "%s", __func__);
680  CHECK_ERROR_REF
681 
682  /* Verify that the library is in the correct state */
683 
684  if (dsObject->internalState >= SML_DATA_SYNC_STATE_SENT_CHANGES)
685  {
686  smlErrorSet(error, SML_ERROR_GENERIC,
687  "The function %s is called to late or more than once.", __func__);
688  goto error;
689  } else {
690  dsObject->internalState = SML_DATA_SYNC_STATE_SENT_CHANGES;
691  }
692  if (dsObject->dsType == SML_SESSION_TYPE_SERVER &&
693  dsObject->actualPackage != SML_PACKAGE_4)
694  {
695  smlErrorSet(error, SML_ERROR_GENERIC,
696  "This is not the server's sync package (%d).",
697  dsObject->actualPackage);
698  goto error;
699  }
700  if (dsObject->dsType == SML_SESSION_TYPE_CLIENT &&
701  dsObject->actualPackage != SML_PACKAGE_3)
702  {
703  smlErrorSet(error, SML_ERROR_GENERIC,
704  "This is not the client's sync package (%d).",
705  dsObject->actualPackage);
706  goto error;
707  }
708 
709  /* iterate over all datastores */
710 
711  GList *o = dsObject->datastores;
712  for (; o; o = o->next) {
713  SmlDataSyncDatastore *datastore = o->data;
714  smlAssert(datastore);
715 
716  int num = g_list_length(datastore->changes);
718  datastore->session,
719  num,
720  smlDataSyncSyncStatusCallback,
721  datastore,
722  error))
723  goto error;
724 
725  int i = 0;
726  for (i = 0; i < num; i++) {
727  SmlDataSyncChange *change = g_list_nth_data(datastore->changes, i);
728  if (!smlDsSessionQueueChange(
729  datastore->session,
730  change->type,
731  change->name,
732  change->data,
733  change->size,
734  datastore->contentType,
735  smlDataSyncChangeStatusCallback,
736  change,
737  error))
738  goto error;
739  }
740 
741  if (!smlDsSessionCloseSync(datastore->session, error))
742  goto error;
743  }
744 
745  /* Send the next package */
746 
747  if (!smlSessionFlush(dsObject->session, TRUE, error))
748  goto error;
749 
750  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
751  return TRUE;
752 error:
753  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
754  return FALSE;
755 }
756 
757 SmlBool smlDataSyncAddMapping(
758  SmlDataSyncObject *dsObject,
759  const char *source,
760  const char *remoteID,
761  const char *localID,
762  SmlError **error)
763 {
764  smlTrace(TRACE_ENTRY, "%s(%s)", __func__, VA_STRING(source));
765 
766  /* check params */
767  CHECK_ERROR_REF
768  smlAssert(dsObject);
769  smlAssert(source);
770  smlAssert(remoteID);
771  smlAssert(localID);
772 
773  /* A map can only be created if a sync from a server was
774  * received. So it makes no sense to cache the mapping.
775  * Therefore the map will be set immediately.
776  */
777 
778  SmlDataSyncDatastore *datastore = NULL;
779  datastore = smlDataSyncGetDatastoreFromSource(dsObject, source, error);
780  if (!datastore)
781  goto error;
782  if (!smlDsSessionQueueMap(datastore->session, remoteID, localID, error))
783  goto error;
784 
785  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
786  return TRUE;
787 error:
788  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
789  return FALSE;
790 }
791 
792 SmlBool smlDataSyncSendMap(SmlDataSyncObject *dsObject, SmlError **error)
793 {
794  smlTrace(TRACE_ENTRY, "%s", __func__);
795  CHECK_ERROR_REF
796  smlAssert(dsObject);
797 
798  /* Verify that the library is in the correct state */
799 
800  if (dsObject->dsType == SML_SESSION_TYPE_SERVER)
801  {
802  smlErrorSet(error, SML_ERROR_GENERIC, "An OMA DS server never sends a map.");
803  goto error;
804  }
805  if (dsObject->dsType == SML_SESSION_TYPE_CLIENT &&
806  dsObject->actualPackage != SML_PACKAGE_5)
807  {
808  smlErrorSet(error, SML_ERROR_GENERIC, "Missing server's sync package.");
809  goto error;
810  }
811 
812  /* iterate over all datastores */
813 
814  GList *o = dsObject->datastores;
815  for (; o; o = o->next) {
816  SmlDataSyncDatastore *datastore = o->data;
817  smlAssert(datastore);
818 
819  /* FIXME: today we ignore the answer */
820  if (!smlDsSessionCloseMap(datastore->session, smlDataSyncMapStatusCallback, datastore, error))
821  goto error;
822  }
823 
824  smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
825  return TRUE;
826 error:
827  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
828  return FALSE;
829 }
830 
831 
833  SmlDataSyncObject *dsObject,
834  SmlError **error)
835 {
836  smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, dsObject, error);
837  smlAssert(dsObject);
838  return smlSessionGetTarget(dsObject->session);
839 }
840 
841 
842 /* close session */
843 
844 void smlDataSyncObjectUnref(SmlDataSyncObject **dsObject)
845 {
846  if (g_atomic_int_dec_and_test(&((*dsObject)->refCount))) {
847 
848  /* stop the dispatcher loop */
849  if ((*dsObject)->thread)
850  smlDataSyncLoopStop((*dsObject));
851 
852  /* stop and free manager */
853  if ((*dsObject)->manager) {
854  smlManagerStop((*dsObject)->manager);
855  smlManagerFree((*dsObject)->manager);
856  }
857  if ((*dsObject)->managerMutex)
858  g_mutex_free((*dsObject)->managerMutex);
859 
860  /* cleanup transport */
861  if ((*dsObject)->tsp) {
862  SmlError *error = NULL;
863  if ((*dsObject)->dsType == SML_SESSION_TYPE_CLIENT &&
864  SML_DATA_SYNC_STATE_CONNECTED >= (*dsObject)->internalState &&
865  (*dsObject)->internalState <= SML_DATA_SYNC_STATE_DISCONNECTED &&
866  !smlTransportDisconnect((*dsObject)->tsp, NULL, &error)) {
867  /* just ignore the error */
868  smlTrace(TRACE_ERROR, "%s: %s",
869  __func__, smlErrorPrint(&error));
870  smlErrorDeref(&error);
871  }
872  /* FIXME: we have to wait here for the disconnect ... */
873  if ((*dsObject)->internalState >= SML_DATA_SYNC_STATE_INITIALIZED &&
874  !smlTransportFinalize((*dsObject)->tsp, &error)) {
875  smlTrace(TRACE_ERROR, "%s: %s",
876  __func__, smlErrorPrint(&error));
877  smlErrorDeref(&error);
878  }
879  smlTransportFree((*dsObject)->tsp);
880  }
881 
882  /* cleanup configuration */
883  if ((*dsObject)->url)
884  smlSafeCFree(&((*dsObject)->url));
885  if ((*dsObject)->target)
886  smlSafeCFree(&((*dsObject)->target));
887  if ((*dsObject)->identifier)
888  smlSafeCFree(&((*dsObject)->identifier));
889  if ((*dsObject)->username)
890  smlSafeCFree(&((*dsObject)->username));
891  if ((*dsObject)->password)
892  smlSafeCFree(&((*dsObject)->password));
893  if ((*dsObject)->fakeDevice)
894  smlSafeCFree(&((*dsObject)->fakeDevice));
895  if ((*dsObject)->fakeManufacturer)
896  smlSafeCFree(&((*dsObject)->fakeManufacturer));
897  if ((*dsObject)->fakeModel)
898  smlSafeCFree(&((*dsObject)->fakeModel));
899  if ((*dsObject)->fakeSoftwareVersion)
900  smlSafeCFree(&((*dsObject)->fakeSoftwareVersion));
901 
902  /* cleanup datastores */
903  while((*dsObject)->datastores) {
904  SmlDataSyncDatastore *datastore = (*dsObject)->datastores->data;
905  (*dsObject)->datastores = g_list_remove(
906  (*dsObject)->datastores,
907  datastore);
908  if (datastore->sourceUri)
909  smlSafeCFree(&(datastore->sourceUri));
910  if (datastore->targetUri)
911  smlSafeCFree(&(datastore->targetUri));
912  if (datastore->contentType)
913  smlSafeCFree(&(datastore->contentType));
914  if (datastore->remoteNext)
915  smlSafeCFree(&(datastore->remoteNext));
916  if (datastore->localNext)
917  smlSafeCFree(&(datastore->localNext));
918  if (datastore->session)
919  smlDsSessionUnref(datastore->session);
920  if (datastore->server)
921  smlDsServerFree(datastore->server);
922 
923  while(datastore->changes) {
924  SmlDataSyncChange *change = datastore->changes->data;
925  datastore->changes = g_list_remove(
926  datastore->changes,
927  change);
928  if (change->name)
929  smlSafeCFree(&(change->name));
930  if (change->data)
931  smlSafeCFree(&(change->data));
932  smlSafeFree((gpointer *)&change);
933  }
934 
935  smlSafeFree((gpointer *)&datastore);
936  }
937 
938  /* cleanup authentication */
939  if ((*dsObject)->auth)
940  smlAuthFree((*dsObject)->auth);
941 
942  /* cleanup session */
943  if ((*dsObject)->session)
944  smlSessionUnref((*dsObject)->session);
945 
946  /* cleanup device information */
947  if ((*dsObject)->localDevInf)
948  smlDevInfUnref((*dsObject)->localDevInf);
949  if ((*dsObject)->remoteDevInf)
950  smlDevInfUnref((*dsObject)->remoteDevInf);
951  if ((*dsObject)->agent)
952  smlDevInfAgentFree((*dsObject)->agent);
953 
954  smlSafeFree((gpointer *) dsObject);
955  }
956 }
957 
958 /* internal functions */
959 
960 void smlDataSyncSendEvent(
961  SmlDataSyncObject *dsObject,
963  void *userdata,
964  SmlError *error)
965 {
966  /* this functionworks synchronous today */
967  smlAssert(dsObject);
968  smlAssert(dsObject->eventCallback);
969  dsObject->eventCallback(dsObject, type, userdata, error);
970 }
971