libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

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") &&
284 !smlTransportSetConfigOption(
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 )&&
296 !smlTransportSetConfigOption(
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") &&
306 !smlTransportSetConfigOption(
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") &&
315 !smlTransportSetConfigOption(
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);
717 if (!smlDsSessionSendSync(
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
832 const SmlLocation *smlDataSyncGetTarget(
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,
962 SmlDataSyncEventType type,
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