data_sync.c
/*
* libsyncml - A syncml protocol implementation
* Copyright (C) 2008-2009 Michael Bell <michael.bell@opensync.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../syncml.h"
#include "../syncml_internals.h"
#include "../sml_error_internals.h"
#include <libsyncml/data_sync_api/defines.h>
#include <libsyncml/data_sync_api/standard.h>
#include <libsyncml/data_sync_api/callbacks.h>
/* required because of function index */
#include <strings.h>
#include "data_sync.h"
#include "data_sync_client.h"
#include "data_sync_server.h"
#include "data_sync_callbacks.h"
#include "data_sync_callbacks.h"
#include "data_sync_devinf.h"
#include "data_sync_loop.h"
#include "transport.h"
#include "libsyncml/objects/sml_ds_server_internals.h"
/* ********************************* */
/* object creation and configuration */
/* ********************************* */
SmlDataSyncObject *smlDataSyncNew(
SmlSessionType dsType,
SmlTransportType tspType,
SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s(%d, %d, %p)", __func__, dsType, tspType, error);
CHECK_ERROR_REF
smlTrace(TRACE_INTERNAL, "%s: libsyncml version: %s", __func__, VERSION);
SmlDataSyncObject *dsObject = smlTryMalloc0(sizeof(SmlDataSyncObject), error);
if (!dsObject)
goto error;
smlDataSyncObjectRef(dsObject);
dsObject->dsType = dsType;
dsObject->tspType = tspType;
dsObject->version = SML_VERSION_11;
dsObject->internalState = SML_DATA_SYNC_STATE_NEW;
dsObject->useNumberOfChanges = TRUE;
dsObject->useTimestampAnchor = TRUE;
dsObject->maxObjSize = SML_DEFAULT_MAX_OBJ_SIZE;
dsObject->maxMsgSize = SML_DEFAULT_MAX_MSG_SIZE;
dsObject->tsp = smlTransportNew(tspType, error);
if (!dsObject->tsp)
goto error;
switch(tspType)
{
case SML_TRANSPORT_OBEX_CLIENT:
dsObject->funcTspInit = smlDataSyncTransportObexClientInit;
dsObject->funcTspConnect = smlDataSyncTransportObexClientConnect;
break;
case SML_TRANSPORT_OBEX_SERVER:
dsObject->funcTspInit = NULL;
dsObject->funcTspConnect = NULL;
break;
case SML_TRANSPORT_HTTP_SERVER:
dsObject->funcTspInit = smlDataSyncTransportHttpServerInit;
dsObject->funcTspConnect = NULL;
break;
case SML_TRANSPORT_HTTP_CLIENT:
dsObject->funcTspInit = smlDataSyncTransportHttpClientInit;
dsObject->funcTspConnect = smlDataSyncTransportHttpClientConnect;
break;
default:
smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown transport type %d used in __func__.",
tspType, __func__);
goto error;
break;
}
switch(dsType)
{
case SML_SESSION_TYPE_SERVER:
dsObject->funcDsInit = smlDataSyncServerInit;
dsObject->funcDsConnect = NULL;
break;
case SML_SESSION_TYPE_CLIENT:
dsObject->funcDsInit = smlDataSyncClientInit;
dsObject->funcDsConnect = NULL;
break;
default:
smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown data sync type %d used in %s.",
dsType, __func__);
goto error;
break;
}
smlTrace(TRACE_EXIT, "%s - %p", __func__, dsObject);
return dsObject;
error:
if (dsObject) {
if (dsObject->tsp)
smlTransportFree(dsObject->tsp);
smlDataSyncObjectUnref(&dsObject);
}
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return NULL;
}
void smlDataSyncObjectRef(SmlDataSyncObject *dsObject)
{
g_atomic_int_inc(&(dsObject->refCount));
}
SmlBool smlDataSyncSetOption(
SmlDataSyncObject *dsObject,
const char *name,
const char *value,
SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, dsObject, VA_STRING(name), VA_STRING(value), error);
CHECK_ERROR_REF
if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_TYPE, name)) {
if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_SERIAL, value))
dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_SERIAL;
if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_BLUETOOTH, value))
dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH;
if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_IRDA, value))
dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_IRDA;
if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_NET, value))
dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_NET;
if (!strcmp(SML_DATA_SYNC_CONFIG_CONNECTION_USB, value))
dsObject->conType = SML_TRANSPORT_CONNECTION_TYPE_USB;
if (!smlTransportSetConnectionType(dsObject->tsp, dsObject->conType, error))
goto error;
} else if (!strcmp(SML_DATA_SYNC_CONFIG_VERSION, name)) {
dsObject->version = SML_VERSION_UNKNOWN;
if (!strcmp("1.0", value))
dsObject->version = SML_VERSION_10;
if (!strcmp("1.1", value))
dsObject->version = SML_VERSION_11;
if (!strcmp("1.2", value))
dsObject->version = SML_VERSION_12;
if (dsObject->version == SML_VERSION_UNKNOWN) {
smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown SyncML version %s.", value);
goto error;
}
} else if (!strcmp(SML_DATA_SYNC_CONFIG_AUTH_TYPE, name)) {
if (!strcmp(value, SML_DATA_SYNC_CONFIG_AUTH_BASIC)) {
dsObject->authType = SML_AUTH_TYPE_BASIC;
} else if (!strcmp(value, SML_DATA_SYNC_CONFIG_AUTH_MD5)) {
dsObject->authType = SML_AUTH_TYPE_MD5;
} else if (!strcmp(value, SML_DATA_SYNC_CONFIG_AUTH_NONE)) {
dsObject->authType = SML_AUTH_TYPE_UNKNOWN;
} else {
// this is an illegal keyword
smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown authentication type %s.", value);
goto error;
}
} else if (!strcmp(SML_TRANSPORT_CONFIG_URL, name)) {
dsObject->url = g_strdup(value);
/* If the Target is not set explicitly
* then the URL is used as the Target in the session header.
* This is only relevant for HTTP clients today.
*/
if (!dsObject->target)
dsObject->target = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_TARGET, name)) {
if (dsObject->target)
smlSafeCFree(&(dsObject->target));
dsObject->target = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_IDENTIFIER, name)) {
if (dsObject->identifier)
smlSafeCFree(&(dsObject->identifier));
if (value && strlen(value)) {
dsObject->identifier = g_strdup(value);
} else {
smlTrace(TRACE_INTERNAL,
"%s: set identifier to NULL", __func__);
}
} else if (!strcmp(SML_DATA_SYNC_CONFIG_AUTH_USERNAME, name)) {
dsObject->username = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_AUTH_PASSWORD, name)) {
dsObject->password = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_WBXML, name)) {
dsObject->useWbxml = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_STRING_TABLE, name)) {
dsObject->useStringTable = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_TIMESTAMP_ANCHOR, name)) {
dsObject->useTimestampAnchor = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_NUMBER_OF_CHANGES, name)) {
dsObject->useNumberOfChanges = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_USE_LOCALTIME, name)) {
dsObject->onlyLocaltime = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_ONLY_REPLACE, name)) {
dsObject->onlyReplace = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_MAX_OBJ_SIZE, name)) {
dsObject->maxObjSize = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_MAX_MSG_SIZE, name)) {
dsObject->maxMsgSize = atoi(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_DEVICE, name)) {
dsObject->fakeDevice = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_MANUFACTURER, name)) {
dsObject->fakeManufacturer = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_MODEL, name)) {
dsObject->fakeModel = g_strdup(value);
} else if (!strcmp(SML_DATA_SYNC_CONFIG_FAKE_SOFTWARE_VERSION, name)) {
dsObject->fakeSoftwareVersion = g_strdup(value);
} else {
if (!smlTransportSetConfigOption(dsObject->tsp, name, value, error))
goto error;
}
// the default is syncml:auth-basic
if ((dsObject->username || dsObject->password) &&
dsObject->authType == SML_AUTH_TYPE_UNKNOWN)
{
smlTrace(TRACE_INTERNAL,
"%s: authType is set to default (syncml:auth-basic)", __func__);
dsObject->authType = SML_AUTH_TYPE_BASIC;
}
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
SmlBool smlDataSyncAddDatastore(SmlDataSyncObject *dsObject,
const char *contentType,
const char *target,
const char *source,
SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %s, %p)", __func__, dsObject, VA_STRING(contentType), VA_STRING(target), VA_STRING(source), error);
CHECK_ERROR_REF
char *lcCT = NULL;
char *lcSource = NULL;
SmlDataSyncDatastore *datastore = smlTryMalloc0(sizeof(SmlDataSyncDatastore), error);
if (!datastore)
goto error;
datastore->dsObject = dsObject;
datastore->syncChanges = NULL;
datastore->syncContexts = NULL;
datastore->sourceUri = g_strdup(source);
datastore->targetUri = g_strdup(target);
datastore->contentType = g_strdup(contentType);
dsObject->datastores = g_list_append(dsObject->datastores, datastore);
/* especially Samsung devices need the datastores during connect */
if (dsObject->tspType == SML_TRANSPORT_OBEX_CLIENT)
{
lcCT = g_ascii_strdown(contentType, strlen(contentType));
lcSource = g_utf8_strdown(source, strlen(source));
if (strstr(lcCT, "vcard") &&
!smlTransportSetConfigOption(
dsObject->tsp,
SML_TRANSPORT_CONFIG_DATASTORE,
SML_TRANSPORT_CONFIG_DATASTORE_CONTACT,
error))
{
goto error;
}
if (strstr(lcCT, "calendar") &&
( strstr(lcSource, "cal") ||
strstr(lcSource, "event")
)&&
!smlTransportSetConfigOption(
dsObject->tsp,
SML_TRANSPORT_CONFIG_DATASTORE,
SML_TRANSPORT_CONFIG_DATASTORE_EVENT,
error))
{
goto error;
}
if (strstr(lcCT, "calendar") &&
strstr(lcSource, "todo") &&
!smlTransportSetConfigOption(
dsObject->tsp,
SML_TRANSPORT_CONFIG_DATASTORE,
SML_TRANSPORT_CONFIG_DATASTORE_TODO,
error))
{
goto error;
}
if (strstr(lcCT, "text/plain") &&
!smlTransportSetConfigOption(
dsObject->tsp,
SML_TRANSPORT_CONFIG_DATASTORE,
SML_TRANSPORT_CONFIG_DATASTORE_NOTE,
error))
{
goto error;
}
smlSafeCFree(&lcCT);
smlSafeCFree(&lcSource);
}
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
if (datastore)
smlSafeFree((gpointer *)&datastore);
if (lcCT)
smlSafeCFree(&lcCT);
if (lcSource)
smlSafeCFree(&lcSource);
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
static SmlDataSyncDatastore *smlDataSyncGetDatastoreFromSource(
SmlDataSyncObject *dsObject,
const char *source,
SmlError **error)
{
CHECK_ERROR_REF
smlAssert(dsObject);
smlAssert(source);
GList *o = dsObject->datastores;
for (; o; o = o->next) {
SmlDataSyncDatastore *datastore = o->data;
if (!strcmp(datastore->sourceUri, source))
return datastore;
}
smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Cannot find datastore for source name %s.", source);
return NULL;
}
/* ***************************** */
/* register callbacks */
/* ***************************** */
void smlDataSyncRegisterEventCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncEventCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->eventCallback = callback;
dsObject->eventUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterGetAlertTypeCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncGetAlertTypeCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->getAlertTypeCallback = callback;
dsObject->getAlertTypeUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterChangeCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncChangeCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->changeCallback = callback;
dsObject->changeUserdata = userdata;
GList *o = dsObject->datastores;
for (;o;o = o->next) {
SmlDataSyncDatastore *datastore = o->data;
if (datastore->session) {
smlDsSessionGetSync(datastore->session,
smlDataSyncSyncCallback, datastore);
smlDsSessionGetChanges(datastore->session,
smlDataSyncChangeCallback, datastore);
}
}
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterChangeStatusCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncChangeStatusCallback callback)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->changeStatusCallback = callback;
/* the userdata is set by the AddChange function */
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterMapCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncMappingCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->mappingCallback = callback;
dsObject->mappingUserdata = userdata;
GList *o = dsObject->datastores;
for (;o;o = o->next) {
SmlDataSyncDatastore *datastore = o->data;
if (datastore->session) {
smlDsSessionGetMapping(datastore->session,
smlDataSyncMappingCallback, datastore);
}
}
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterGetAnchorCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncGetAnchorCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->getAnchorCallback = callback;
dsObject->getAnchorUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterSetAnchorCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncSetAnchorCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->setAnchorCallback = callback;
dsObject->setAnchorUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterWriteDevInfCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncWriteDevInfCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->writeDevInfCallback = callback;
dsObject->writeDevInfUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterReadDevInfCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncReadDevInfCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->readDevInfCallback = callback;
dsObject->readDevInfUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
void smlDataSyncRegisterHandleRemoteDevInfCallback(
SmlDataSyncObject *dsObject,
SmlDataSyncHandleRemoteDevInfCallback callback,
void *userdata)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
smlAssert(dsObject);
smlAssert(callback);
dsObject->handleRemoteDevInfCallback = callback;
dsObject->handleRemoteDevInfUserdata = userdata;
smlTrace(TRACE_EXIT, "%s", __func__);
}
/* ***************************** */
/* init session */
/* ***************************** */
SmlBool smlDataSyncInit(SmlDataSyncObject *dsObject, SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
CHECK_ERROR_REF
smlAssert(dsObject);
if (!dsObject->identifier)
dsObject->identifier = smlDataSyncDevInfGetIdentifier();
dsObject->managerMutex = g_mutex_new();
if (dsObject->funcTspInit &&
!dsObject->funcTspInit(dsObject, error))
goto error;
if (!dsObject->funcDsInit(dsObject, error))
goto error;
dsObject->internalState = SML_DATA_SYNC_STATE_INITIALIZED;
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
SmlBool smlDataSyncRun(SmlDataSyncObject *dsObject, SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
CHECK_ERROR_REF
/* If a server was initialized then you cannot do more
* than waiting for the remote client.
*/
if (dsObject->funcTspConnect &&
!dsObject->funcTspConnect(dsObject, error))
goto error;
if (dsObject->funcDsConnect &&
!dsObject->funcDsConnect(dsObject, error))
goto error;
if (!smlDataSyncLoopStart(dsObject, error))
goto error;
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
/* synchronize */
SmlBool smlDataSyncAddChange(
SmlDataSyncObject *dsObject,
const char *source,
SmlChangeType type,
const char *name,
const char *data,
unsigned int size,
void *userdata, /* for SmlDataSyncChangeStatusCallback */
SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s(%s)", __func__, VA_STRING(source));
/* check params */
CHECK_ERROR_REF
smlAssert(dsObject);
smlAssert(source);
smlAssert(type);
/* create a new change */
SmlDataSyncChange *change = smlTryMalloc0(sizeof(SmlDataSyncChange), error);
if (!change)
goto error;
/* fill the new change */
change->type = type;
change->name = g_strdup(name);
change->userdata = userdata;
/* determine the datastore */
change->datastore = smlDataSyncGetDatastoreFromSource(dsObject, source, error);
if (!change->datastore)
goto error;
SmlDataSyncDatastore *datastore = change->datastore;
/* copy data */
if (data) {
smlAssert(datastore->contentType);
smlAssert(index(datastore->contentType, '/'));
size_t appClassLength = ((size_t) index(datastore->contentType, '/')) -
((size_t) datastore->contentType);
if ( ( strstr(datastore->contentType, SML_CONTENT_TYPE_APPLICATION) == datastore->contentType &&
appClassLength == strlen(SML_CONTENT_TYPE_APPLICATION) ) ||
( strstr(datastore->contentType, SML_CONTENT_TYPE_AUDIO) == datastore->contentType &&
appClassLength == strlen(SML_CONTENT_TYPE_AUDIO) ) ||
( strstr(datastore->contentType, SML_CONTENT_TYPE_IMAGE) == datastore->contentType &&
appClassLength == strlen(SML_CONTENT_TYPE_IMAGE) ) ||
( strstr(datastore->contentType, SML_CONTENT_TYPE_MESSAGE) == datastore->contentType &&
appClassLength == strlen(SML_CONTENT_TYPE_MESSAGE) ) ||
( strstr(datastore->contentType, SML_CONTENT_TYPE_VIDEO) == datastore->contentType &&
appClassLength == strlen(SML_CONTENT_TYPE_AUDIO) ) )
{
/* binary data must be base64 encoded */
change->data = g_base64_encode((const unsigned char *) data, size);
if (!change->data) {
smlErrorSet(error, SML_ERROR_GENERIC,
"The base 64 encoding of glib failed.");
goto error;
}
change->size = strlen(change->data);
} else {
change->data = smlTryMalloc0(size+1, error);
if (!change->data)
goto error;
memcpy(change->data, data, size);
change->size = size;
}
} else {
change->data = NULL;
change->size = 0;
}
/* append change to datastore */
datastore->changes = g_list_append(datastore->changes, change);
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
SmlBool smlDataSyncSendChanges(SmlDataSyncObject *dsObject, SmlError **error)
{
/* This means that all alerts were received
* and all changes were added.
* So let us flush the session. */
smlTrace(TRACE_ENTRY, "%s", __func__);
CHECK_ERROR_REF
/* Verify that the library is in the correct state */
if (dsObject->internalState >= SML_DATA_SYNC_STATE_SENT_CHANGES)
{
smlErrorSet(error, SML_ERROR_GENERIC,
"The function %s is called to late or more than once.", __func__);
goto error;
} else {
dsObject->internalState = SML_DATA_SYNC_STATE_SENT_CHANGES;
}
if (dsObject->dsType == SML_SESSION_TYPE_SERVER &&
dsObject->actualPackage != SML_PACKAGE_4)
{
smlErrorSet(error, SML_ERROR_GENERIC,
"This is not the server's sync package (%d).",
dsObject->actualPackage);
goto error;
}
if (dsObject->dsType == SML_SESSION_TYPE_CLIENT &&
dsObject->actualPackage != SML_PACKAGE_3)
{
smlErrorSet(error, SML_ERROR_GENERIC,
"This is not the client's sync package (%d).",
dsObject->actualPackage);
goto error;
}
/* iterate over all datastores */
GList *o = dsObject->datastores;
for (; o; o = o->next) {
SmlDataSyncDatastore *datastore = o->data;
smlAssert(datastore);
int num = g_list_length(datastore->changes);
if (!smlDsSessionSendSync(
datastore->session,
num,
smlDataSyncSyncStatusCallback,
datastore,
error))
goto error;
int i = 0;
for (i = 0; i < num; i++) {
SmlDataSyncChange *change = g_list_nth_data(datastore->changes, i);
if (!smlDsSessionQueueChange(
datastore->session,
change->type,
change->name,
change->data,
change->size,
datastore->contentType,
smlDataSyncChangeStatusCallback,
change,
error))
goto error;
}
if (!smlDsSessionCloseSync(datastore->session, error))
goto error;
}
/* Send the next package */
if (!smlSessionFlush(dsObject->session, TRUE, error))
goto error;
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
SmlBool smlDataSyncAddMapping(
SmlDataSyncObject *dsObject,
const char *source,
const char *remoteID,
const char *localID,
SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s(%s)", __func__, VA_STRING(source));
/* check params */
CHECK_ERROR_REF
smlAssert(dsObject);
smlAssert(source);
smlAssert(remoteID);
smlAssert(localID);
/* A map can only be created if a sync from a server was
* received. So it makes no sense to cache the mapping.
* Therefore the map will be set immediately.
*/
SmlDataSyncDatastore *datastore = NULL;
datastore = smlDataSyncGetDatastoreFromSource(dsObject, source, error);
if (!datastore)
goto error;
if (!smlDsSessionQueueMap(datastore->session, remoteID, localID, error))
goto error;
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
SmlBool smlDataSyncSendMap(SmlDataSyncObject *dsObject, SmlError **error)
{
smlTrace(TRACE_ENTRY, "%s", __func__);
CHECK_ERROR_REF
smlAssert(dsObject);
/* Verify that the library is in the correct state */
if (dsObject->dsType == SML_SESSION_TYPE_SERVER)
{
smlErrorSet(error, SML_ERROR_GENERIC, "An OMA DS server never sends a map.");
goto error;
}
if (dsObject->dsType == SML_SESSION_TYPE_CLIENT &&
dsObject->actualPackage != SML_PACKAGE_5)
{
smlErrorSet(error, SML_ERROR_GENERIC, "Missing server's sync package.");
goto error;
}
/* iterate over all datastores */
GList *o = dsObject->datastores;
for (; o; o = o->next) {
SmlDataSyncDatastore *datastore = o->data;
smlAssert(datastore);
/* FIXME: today we ignore the answer */
if (!smlDsSessionCloseMap(datastore->session, smlDataSyncMapStatusCallback, datastore, error))
goto error;
}
smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
return TRUE;
error:
smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
return FALSE;
}
const SmlLocation *smlDataSyncGetTarget(
SmlDataSyncObject *dsObject,
SmlError **error)
{
smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, dsObject, error);
smlAssert(dsObject);
return smlSessionGetTarget(dsObject->session);
}
/* close session */
void smlDataSyncObjectUnref(SmlDataSyncObject **dsObject)
{
if (g_atomic_int_dec_and_test(&((*dsObject)->refCount))) {
/* stop the dispatcher loop */
if ((*dsObject)->thread)
smlDataSyncLoopStop((*dsObject));
/* stop and free manager */
if ((*dsObject)->manager) {
smlManagerStop((*dsObject)->manager);
smlManagerFree((*dsObject)->manager);
}
if ((*dsObject)->managerMutex)
g_mutex_free((*dsObject)->managerMutex);
/* cleanup transport */
if ((*dsObject)->tsp) {
SmlError *error = NULL;
if ((*dsObject)->dsType == SML_SESSION_TYPE_CLIENT &&
SML_DATA_SYNC_STATE_CONNECTED >= (*dsObject)->internalState &&
(*dsObject)->internalState <= SML_DATA_SYNC_STATE_DISCONNECTED &&
!smlTransportDisconnect((*dsObject)->tsp, NULL, &error)) {
/* just ignore the error */
smlTrace(TRACE_ERROR, "%s: %s",
__func__, smlErrorPrint(&error));
smlErrorDeref(&error);
}
/* FIXME: we have to wait here for the disconnect ... */
if ((*dsObject)->internalState >= SML_DATA_SYNC_STATE_INITIALIZED &&
!smlTransportFinalize((*dsObject)->tsp, &error)) {
smlTrace(TRACE_ERROR, "%s: %s",
__func__, smlErrorPrint(&error));
smlErrorDeref(&error);
}
smlTransportFree((*dsObject)->tsp);
}
/* cleanup configuration */
if ((*dsObject)->url)
smlSafeCFree(&((*dsObject)->url));
if ((*dsObject)->target)
smlSafeCFree(&((*dsObject)->target));
if ((*dsObject)->identifier)
smlSafeCFree(&((*dsObject)->identifier));
if ((*dsObject)->username)
smlSafeCFree(&((*dsObject)->username));
if ((*dsObject)->password)
smlSafeCFree(&((*dsObject)->password));
if ((*dsObject)->fakeDevice)
smlSafeCFree(&((*dsObject)->fakeDevice));
if ((*dsObject)->fakeManufacturer)
smlSafeCFree(&((*dsObject)->fakeManufacturer));
if ((*dsObject)->fakeModel)
smlSafeCFree(&((*dsObject)->fakeModel));
if ((*dsObject)->fakeSoftwareVersion)
smlSafeCFree(&((*dsObject)->fakeSoftwareVersion));
/* cleanup datastores */
while((*dsObject)->datastores) {
SmlDataSyncDatastore *datastore = (*dsObject)->datastores->data;
(*dsObject)->datastores = g_list_remove(
(*dsObject)->datastores,
datastore);
if (datastore->sourceUri)
smlSafeCFree(&(datastore->sourceUri));
if (datastore->targetUri)
smlSafeCFree(&(datastore->targetUri));
if (datastore->contentType)
smlSafeCFree(&(datastore->contentType));
if (datastore->remoteNext)
smlSafeCFree(&(datastore->remoteNext));
if (datastore->localNext)
smlSafeCFree(&(datastore->localNext));
if (datastore->session)
smlDsSessionUnref(datastore->session);
if (datastore->server)
smlDsServerFree(datastore->server);
while(datastore->changes) {
SmlDataSyncChange *change = datastore->changes->data;
datastore->changes = g_list_remove(
datastore->changes,
change);
if (change->name)
smlSafeCFree(&(change->name));
if (change->data)
smlSafeCFree(&(change->data));
smlSafeFree((gpointer *)&change);
}
smlSafeFree((gpointer *)&datastore);
}
/* cleanup authentication */
if ((*dsObject)->auth)
smlAuthFree((*dsObject)->auth);
/* cleanup session */
if ((*dsObject)->session)
smlSessionUnref((*dsObject)->session);
/* cleanup device information */
if ((*dsObject)->localDevInf)
smlDevInfUnref((*dsObject)->localDevInf);
if ((*dsObject)->remoteDevInf)
smlDevInfUnref((*dsObject)->remoteDevInf);
if ((*dsObject)->agent)
smlDevInfAgentFree((*dsObject)->agent);
smlSafeFree((gpointer *) dsObject);
}
}
/* internal functions */
void smlDataSyncSendEvent(
SmlDataSyncObject *dsObject,
SmlDataSyncEventType type,
void *userdata,
SmlError *error)
{
/* this functionworks synchronous today */
smlAssert(dsObject);
smlAssert(dsObject->eventCallback);
dsObject->eventCallback(dsObject, type, userdata, error);
}
smlDsSessionGetChanges
void smlDsSessionGetChanges(SmlDsSession *dsession, SmlDsSessionChangesCb chgCallback, void *userdata)
Gets a already received sync command.
Definition: sml_ds_server.c:1022
SmlDataSyncDatastore
This object represents an OMA DS datastore.
Definition: data_sync.h:93
smlTransportSetConfigOption
SmlBool smlTransportSetConfigOption(SmlTransport *tsp, const char *name, const char *value, SmlError **error)
Sets a configuration parameter.
Definition: sml_transport.c:883
smlErrorPrint
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
Definition: sml_error.c:299
smlTransportFinalize
SmlBool smlTransportFinalize(SmlTransport *tsp, SmlError **error)
Finalizes the transport.
Definition: sml_transport.c:1104
smlManagerStop
void smlManagerStop(SmlManager *manager)
Stops the active manager part.
Definition: sml_manager.c:565
SmlDataSyncObject
This is the central synchronization object.
Definition: data_sync.h:110
smlSessionFlush
SmlBool smlSessionFlush(SmlSession *session, SmlBool final, SmlError **error)
Flushes a session.
Definition: sml_session.c:2010
SmlDataSyncEventType
SmlDataSyncEventType
These are all possible events which the high level API sends.
Definition: standard.h:45
smlTransportSetConnectionType
SmlBool smlTransportSetConnectionType(SmlTransport *tsp, SmlTransportConnectionType type, SmlError **error)
Sets a configuration parameter.
Definition: sml_transport.c:931
smlDataSyncGetTarget
const SmlLocation * smlDataSyncGetTarget(SmlDataSyncObject *dsObject, SmlError **error)
Definition: data_sync.c:832
smlTransportNew
SmlTransport * smlTransportNew(SmlTransportType type, SmlError **error)
Creates a new transport.
Definition: sml_transport.c:721
smlDsSessionSendSync
SmlBool smlDsSessionSendSync(SmlDsSession *dsession, unsigned int num_changes, SmlStatusReplyCb callback, void *userdata, SmlError **error)
Start the sync command to send to the other side.
Definition: sml_ds_server.c:1077
smlDsSessionCloseMap
SmlBool smlDsSessionCloseMap(SmlDsSession *dsession, SmlStatusReplyCb callback, void *userdata, SmlError **error)
Closes the map command.
Definition: sml_ds_server.c:1214
smlTransportFree
void smlTransportFree(SmlTransport *tsp)
Frees the given transport.
Definition: sml_transport.c:810
smlTrace
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
Definition: sml_support.c:120
SmlLocation
Definition: sml_elements_internals.h:40
smlDsSessionCloseSync
SmlBool smlDsSessionCloseSync(SmlDsSession *dsession, SmlError **error)
Closes the sync command.
Definition: sml_ds_server.c:1160
smlTryMalloc0
void * smlTryMalloc0(long n_bytes, SmlError **error)
Safely mallocs.
Definition: sml_support.c:335
smlErrorSet
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.
Definition: sml_error.c:355
SmlDataSyncChange
This internal structure represents exactly one change.
Definition: data_sync.h:207
SmlError
Represent an error.
Definition: sml_error_internals.h:29