/*
 * libsyncml - A syncml protocol implementation
 * Copyright (C) 2005  Armin Bauer <armin.bauer@opensync.org>
 * Copyright (C) 2008  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 "tests/support.h"

#include <libsyncml/objects/sml_ds_server.h>
#include <libsyncml/objects/sml_auth.h>

#include <libsyncml/objects/sml_devinf_obj.h>

#include <libsyncml/data_sync_api/sml_location.h>
#include <libsyncml/data_sync_api/sml_data_sync_defines.h>

#include <libsyncml/sml_error_internals.h>

#include <config.h>
#include <unistd.h>

#define NUM_SESSIONS 30

typedef struct managerTracker {
	SmlManager *manager;
	SmlSession *session;
	SmlDsSession *dssessions[NUM_SESSIONS];
	SmlDsServer *ds[3];
} managerTracker;

unsigned int init_alerts_received;
unsigned int alerts_received;
unsigned int syncs_received;
unsigned int sans_received;
unsigned int sync_ends_received;
unsigned int changes_received;
unsigned int replies_received;
int adds_received;
unsigned int add_replies_received;
int deletes_received;
unsigned int delete_replies_received;
int modifies_received;
unsigned int modify_replies_received;
int mappings_received;
unsigned int map_replies_received;
unsigned int session_ends;

unsigned int transport_errors;
unsigned int num_sessions;
unsigned int num_finals;
unsigned int num_end;
int num_disconnects;
unsigned int session_errors;

/* This is a sync test only and not a test of large object support.
 * Therefore all commands must be put into one message.
 * This means one message per package.
 */
#define TEST_DEFAULT_MAX_MSG_SIZE    1024000
#define TEST_DEFAULT_MAX_OBJ_SIZE    1024000
unsigned int num_changes;
GError *eventError;

void reset_testbed()
{
	init_alerts_received = 0;
	alerts_received = 0;
	syncs_received = 0;
	sans_received = 0;
	sync_ends_received = 0;
	changes_received = 0;
	replies_received = 0;
	adds_received = 0;
	add_replies_received = 0;
	deletes_received = 0;
	delete_replies_received = 0;
	modifies_received = 0;
	modify_replies_received = 0;
	session_ends = 0;

	transport_errors = 0;
	num_sessions = 0;
	num_finals = 0;
	num_end = 0;
	num_disconnects = 0;
	session_errors = 0;

	num_changes = 0;
	eventError = NULL;

	setup_testbed(NULL);
}

static void _manager_event(SmlManager *manager, SmlManagerEventType type, SmlSession *session, const GError *error, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, manager, type, session, error, userdata);
	managerTracker *tracker = userdata;
	smlAssert(manager);
	smlAssert(userdata);
	
	switch (type) {
		case SML_MANAGER_SESSION_ESTABLISHED:
		case SML_MANAGER_SESSION_FLUSH:
		case SML_MANAGER_CONNECT_DONE:
			break;
		case SML_MANAGER_DISCONNECT_DONE:
			g_atomic_int_inc(&num_disconnects);
			break;
		case SML_MANAGER_TRANSPORT_ERROR:
			smlTrace(TRACE_INTERNAL, "%s - error: %s", __func__, GET_ERROR_MESSAGE(error));
			eventError = g_error_copy(error);
			transport_errors++;
			break;
		case SML_MANAGER_SESSION_NEW:
			smlAssert(session);
			tracker->session = session;
			num_sessions++;
			smlSessionRef(session);
			break;
		case SML_MANAGER_SESSION_FINAL:
			num_finals++;
			break;
		case SML_MANAGER_SESSION_END:
			num_end++;
			break;
		case SML_MANAGER_SESSION_ERROR:
		case SML_MANAGER_SESSION_WARNING:
			smlTrace(TRACE_INTERNAL, "%s - error: %s", __func__, GET_ERROR_MESSAGE(error));
			if (eventError)
				SML_ERROR_FREE(eventError);
			eventError = g_error_copy(error);
			session_errors++;
			break;
		default:
			sml_fail_unless(FALSE, "An unexpected manager event %d was received.", type);
			break;
	}
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

static void _recv_init_alert(SmlDsSession *dsession, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, userdata);
	managerTracker *tracker = userdata;
	
	if (tracker->ds[0] == smlDsSessionGetServer(dsession))
		tracker->dssessions[0] = dsession;
	else if (tracker->ds[1] == smlDsSessionGetServer(dsession))
		tracker->dssessions[1] = dsession;
	else if (tracker->ds[2] == smlDsSessionGetServer(dsession))
		tracker->dssessions[2] = dsession;
	
	smlDsSessionRef(dsession);
	
	init_alerts_received++;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

static gboolean _recv_alert(SmlDsSession *dsession, SmlAlertType type, const char *last, const char *next, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %s, %p)", __func__, dsession, type, VA_STRING(last), VA_STRING(next), userdata);
	
	sml_fail_unless(last != NULL, NULL);
	sml_fail_unless(next != NULL, NULL);
	
	alerts_received++;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
	return TRUE;
}

static void _alert_reply(SmlSession *dsession, SmlStatus *status, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p)", __func__, dsession);
	
	sml_fail_unless(status != NULL, NULL);
	
	if (GPOINTER_TO_INT(userdata) == 1) {
		sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_SUCCESS, NULL);
	} else {
		sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_FATAL, NULL);
	}
	
	replies_received++;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

static void _sync_reply(SmlSession *dsession, SmlStatus *status, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p)", __func__, dsession);
	
	sml_fail_unless(status != NULL, NULL);
	
	if (GPOINTER_TO_INT(userdata) == 1) {
		sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_SUCCESS, NULL);
	} else {
		sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_FATAL, NULL);
	}
	
	replies_received++;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

static void _add_reply(SmlDsSession *session, SmlStatus *status, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
	
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_SUCCESS, NULL);
	sml_fail_unless(GPOINTER_TO_INT(userdata) == 1 || GPOINTER_TO_INT(userdata) == 2, NULL);

	/* newuid is only supplied by mapping callback */
	
	add_replies_received++;

	smlTrace(TRACE_EXIT, "%s", __func__);
}

static void _modify_reply(SmlDsSession *session, SmlStatus *status, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
	
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_SUCCESS, NULL);
	sml_fail_unless(GPOINTER_TO_INT(userdata) == 1, NULL);

	modify_replies_received++;

	smlTrace(TRACE_EXIT, "%s", __func__);
}

static void _delete_reply(SmlDsSession *session, SmlStatus *status, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
	
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_SUCCESS, NULL);
	sml_fail_unless(GPOINTER_TO_INT(userdata) == 1, NULL);

	delete_replies_received++;

	smlTrace(TRACE_EXIT, "%s", __func__);
}

static void _map_reply(SmlSession *dsession, SmlStatus *status, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, userdata);
	
	sml_fail_unless(status != NULL, NULL);
	sml_fail_unless(smlStatusGetClass(status) == SML_ERRORCLASS_SUCCESS, NULL);
	
	map_replies_received++;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

static SmlErrorType _recv_san(SmlDsServer *server, SmlSession *session, SmlAlertType type, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, server, session, type, userdata);
	sml_fail_unless(GPOINTER_TO_INT(userdata) == 1, NULL);
	
	sml_fail_unless(type == SML_ALERT_TWO_WAY_BY_SERVER, NULL);
	sans_received++;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
	return SML_NO_ERROR;
}

static void _recv_sync(SmlDsSession *dsession, gsize numChanges, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %d, %p)", __func__, dsession, numChanges, userdata);
	
	sml_fail_unless(numChanges == num_changes, NULL);
	syncs_received++;
		
	smlTrace(TRACE_EXIT, "%s", __func__);
}

static gboolean _recv_changes(SmlDsSession *dsession, SmlDataSyncChangeItem *item, void *userdata, GError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, dsession, item, userdata, error);

	if (sml_data_sync_change_item_get_action(item) == SML_CHANGE_ADD) {
		g_atomic_int_add(&adds_received, 1);
		sml_fail_unless(!strcmp(sml_location_get_uri(sml_data_sync_change_item_get_location(item)), "uid"), NULL);
		sml_fail_unless(!strncmp(sml_data_sync_change_item_get_data(item), "data", strlen(sml_data_sync_change_item_get_data(item))), NULL);
		sml_fail_unless(strlen(sml_data_sync_change_item_get_data(item)) == 4, NULL);
	} else if (sml_data_sync_change_item_get_action(item) == SML_CHANGE_REPLACE) {
		g_atomic_int_add(&modifies_received, 1);
		sml_fail_unless(!strcmp(sml_location_get_uri(sml_data_sync_change_item_get_location(item)), "uid"), NULL);
		sml_fail_unless(!strncmp(sml_data_sync_change_item_get_data(item), "newdata", strlen(sml_data_sync_change_item_get_data(item))), NULL);
		sml_fail_unless(strlen(sml_data_sync_change_item_get_data(item)) == 7, NULL);
	} else if (sml_data_sync_change_item_get_action(item) == SML_CHANGE_DELETE) {
		g_atomic_int_add(&deletes_received, 1);
		sml_fail_unless(!strcmp(sml_location_get_uri(sml_data_sync_change_item_get_location(item)), "uid"), NULL);
		sml_fail_unless(!sml_data_sync_change_item_get_data(item), NULL);
	} else {
		sml_fail_unless(FALSE, "An unexpected SyncML change type %d was received.", sml_data_sync_change_item_get_action(item));
	}

	smlTrace(TRACE_EXIT, "%s", __func__);
	return TRUE;
}

static void _recv_map(SmlDsSession *dsession, SmlMapItem *item, void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__,dsession, item, userdata);
	
	g_atomic_int_add(&mappings_received, 1);
		
	smlTrace(TRACE_EXIT, "%s", __func__);
}

START_TEST (sync_multi_start)
{
	reset_testbed();
	
	GError *error = NULL;

	SmlTransport *server = smlTransportNew(SML_TRANSPORT_HTTP_SERVER, &error);
	SmlTransport *client = smlTransportNew(SML_TRANSPORT_HTTP_CLIENT, &error);
	
	sml_fail_unless(smlTransportSetConfigOption(client, "URL", "http://127.0.0.1:12012", &error), NULL);

	sml_fail_unless(smlTransportSetConfigOption(server, "PORT", "12012", &error), NULL);
	
	managerTracker *clienttracker = g_malloc0(sizeof(managerTracker));
	SmlManager *clientmanager = clienttracker->manager = smlManagerNew(client, &error);
	smlManagerSetEventCallback(clienttracker->manager, _manager_event, clienttracker);
	managerTracker *servertracker = g_malloc0(sizeof(managerTracker));
	SmlManager *servermanager = servertracker->manager = smlManagerNew(server, &error);
	smlManagerSetEventCallback(servertracker->manager, _manager_event, servertracker);
	smlManagerSetLocalMaxMsgSize(servertracker->manager, TEST_DEFAULT_MAX_MSG_SIZE);
	smlManagerSetLocalMaxObjSize(servertracker->manager, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	sml_fail_unless(error == NULL, "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(server, &error), "%s", GET_ERROR_MESSAGE(error));

	sml_fail_unless(smlManagerStart(clientmanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlManagerStart(servermanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "test");
	
	SmlLocation *loc1 = sml_location_new();
	sml_fail_unless(loc1 != NULL, NULL);
	sml_location_set_uri(loc1, "test1");
	
	SmlLocation *loc2 = sml_location_new();
	sml_fail_unless(loc2 != NULL, NULL);
	sml_location_set_uri(loc2, "test2");
	
	SmlLocation *loc3 = sml_location_new();
	sml_fail_unless(loc3 != NULL, NULL);
	sml_location_set_uri(loc3, "test3");
	
	clienttracker->ds[0] = smlDsClientNew(SML_ELEMENT_TEXT_VCARD, loc1, loc1, &error);
	clienttracker->ds[1] = smlDsClientNew(SML_ELEMENT_TEXT_VCAL, loc2, loc2, &error);
	clienttracker->ds[2] = smlDsClientNew(SML_ELEMENT_TEXT_PLAIN, loc3, loc3, &error);
	smlDsServerRegister(clienttracker->ds[0], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[1], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[2], clientmanager, &error);
				
	servertracker->ds[0] = smlDsServerNew(SML_ELEMENT_TEXT_VCARD, loc1, &error);
	servertracker->ds[1] = smlDsServerNew(SML_ELEMENT_TEXT_VCAL, loc2, &error);
	servertracker->ds[2] = smlDsServerNew(SML_ELEMENT_TEXT_PLAIN, loc3, &error);
	smlDsServerSetConnectCallback(servertracker->ds[0], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[1], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[2], _recv_init_alert, servertracker);
	smlDsServerRegister(servertracker->ds[0], servermanager, &error);
	smlDsServerRegister(servertracker->ds[1], servermanager, &error);
	smlDsServerRegister(servertracker->ds[2], servermanager, &error);
	
	g_object_unref(loc1);
	g_object_unref(loc2);
	g_object_unref(loc3);
	
	/* The authenticator */
	/* The authenticator */
	SmlAuthenticator *auth = smlAuthNew(&error);
	smlAuthSetEnable(auth, FALSE);
	smlAuthRegister(auth, clientmanager, &error);
	
	/* The authenticator */
	SmlAuthenticator *auth2 = smlAuthNew(&error);
	smlAuthSetEnable(auth2, FALSE);
	smlAuthRegister(auth2, servermanager, &error);
	
	SmlSession *session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 0, 0, &error);
	
	sml_fail_unless(smlManagerSessionAdd(clientmanager, session, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	g_object_unref(loc);
	
	clienttracker->dssessions[0] = smlDsServerSendAlert(clienttracker->ds[0], session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[1] = smlDsServerSendAlert(clienttracker->ds[1], session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[2] = smlDsServerSendAlert(clienttracker->ds[2], session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(session, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	while (init_alerts_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	smlDsSessionGetAlert(servertracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionEnd(servertracker->session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSessionUnref(servertracker->session); /* unref for ref from callback */
	smlSessionUnref(clienttracker->session); /* unref for ref from callback */
	smlSessionUnref(clienttracker->session); /* unref for smlSessionNew */
	
	while (num_end < 2 || replies_received < 3 || num_finals < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(init_alerts_received == 3, NULL);
	sml_fail_unless(alerts_received == 3, NULL);
	sml_fail_unless(syncs_received == 0, NULL);
	sml_fail_unless(sync_ends_received == 0, NULL);
	sml_fail_unless(changes_received == 0, NULL);
	sml_fail_unless(replies_received == 3, NULL);
	sml_fail_unless(adds_received == 0, NULL);
	sml_fail_unless(add_replies_received == 0, NULL);
	sml_fail_unless(deletes_received == 0, NULL);
	sml_fail_unless(delete_replies_received == 0, NULL);
	sml_fail_unless(modifies_received == 0, NULL);
	sml_fail_unless(modify_replies_received == 0, NULL);
	sml_fail_unless(transport_errors == 0, NULL);
	sml_fail_unless(num_sessions == 2, NULL);
	sml_fail_unless(num_finals == 2, NULL);
	sml_fail_unless(num_end == 2, NULL);
	sml_fail_unless(session_errors == 0, NULL);
	
	smlDsSessionUnref(clienttracker->dssessions[0]);
	smlDsSessionUnref(clienttracker->dssessions[1]);
	smlDsSessionUnref(clienttracker->dssessions[2]);
	
	smlDsSessionUnref(servertracker->dssessions[0]);
	smlDsSessionUnref(servertracker->dssessions[1]);
	smlDsSessionUnref(servertracker->dssessions[2]);
	
	smlDsServerFree(clienttracker->ds[0]);
	smlDsServerFree(clienttracker->ds[1]);
	smlDsServerFree(clienttracker->ds[2]);
	
	smlDsServerFree(servertracker->ds[0]);
	smlDsServerFree(servertracker->ds[1]);
	smlDsServerFree(servertracker->ds[2]);
	
	g_free(clienttracker);
	g_free(servertracker);
	
	smlManagerStop(clientmanager);
	smlManagerStop(servermanager);

	while(num_disconnects < 2) {
		smlManagerDispatch(clientmanager);
		smlManagerDispatch(servermanager);
	}
	
	smlManagerFree(clientmanager);
	smlManagerFree(servermanager);

	smlAuthFree(auth);
	smlAuthFree(auth2);
	
	sml_fail_unless(smlTransportFinalize(server, &error), NULL);
	sml_fail_unless(smlTransportFinalize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	
	smlTransportFree(server);
	smlTransportFree(client);
}
END_TEST

/* client -- 3 * alert ---> server
 * server -- statuses, 3 * alert ---> client
 * client -- statuses, num * add, num * replace, num * delete ---> server
 * server -- statuses ---> client
 */
START_TEST (sync_multi_stress)
{
	reset_testbed();

	unsigned int num_items = 10;
	num_changes = 3 * num_items;
	
	GError *error = NULL;

	SmlTransport *server = smlTransportNew(SML_TRANSPORT_HTTP_SERVER, &error);
	SmlTransport *client = smlTransportNew(SML_TRANSPORT_HTTP_CLIENT, &error);
	
	sml_fail_unless(smlTransportSetConfigOption(client, "URL", "http://127.0.0.1:12013", &error), NULL);

	sml_fail_unless(smlTransportSetConfigOption(server, "PORT", "12013", &error), NULL);
	
	managerTracker *clienttracker = g_malloc0(sizeof(managerTracker));
	SmlManager *clientmanager = clienttracker->manager = smlManagerNew(client, &error);
	smlManagerSetEventCallback(clienttracker->manager, _manager_event, clienttracker);
	managerTracker *servertracker = g_malloc0(sizeof(managerTracker));
	SmlManager *servermanager = servertracker->manager = smlManagerNew(server, &error);
	smlManagerSetEventCallback(servertracker->manager, _manager_event, servertracker);
	smlManagerSetLocalMaxMsgSize(servertracker->manager, TEST_DEFAULT_MAX_MSG_SIZE);
	smlManagerSetLocalMaxObjSize(servertracker->manager, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	sml_fail_unless(error == NULL, "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(server, &error), "%s", GET_ERROR_MESSAGE(error));

	sml_fail_unless(smlManagerStart(clientmanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlManagerStart(servermanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "test");
	
	SmlLocation *loc1 = sml_location_new();
	sml_fail_unless(loc1 != NULL, NULL);
	sml_location_set_uri(loc1, "test1");
	
	SmlLocation *loc2 = sml_location_new();
	sml_fail_unless(loc2 != NULL, NULL);
	sml_location_set_uri(loc2, "test2");
	
	SmlLocation *loc3 = sml_location_new();
	sml_fail_unless(loc3 != NULL, NULL);
	sml_location_set_uri(loc3, "test3");
	
	clienttracker->ds[0] = smlDsClientNew(SML_ELEMENT_TEXT_VCARD, loc1, loc1, &error);
	clienttracker->ds[1] = smlDsClientNew(SML_ELEMENT_TEXT_VCAL, loc2, loc2, &error);
	clienttracker->ds[2] = smlDsClientNew(SML_ELEMENT_TEXT_PLAIN, loc3, loc3, &error);
	smlDsServerRegister(clienttracker->ds[0], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[1], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[2], clientmanager, &error);
				
	servertracker->ds[0] = smlDsServerNew(SML_ELEMENT_TEXT_VCARD, loc1, &error);
	servertracker->ds[1] = smlDsServerNew(SML_ELEMENT_TEXT_VCAL, loc2, &error);
	servertracker->ds[2] = smlDsServerNew(SML_ELEMENT_TEXT_PLAIN, loc3, &error);
	smlDsServerSetConnectCallback(servertracker->ds[0], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[1], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[2], _recv_init_alert, servertracker);
	smlDsServerRegister(servertracker->ds[0], servermanager, &error);
	smlDsServerRegister(servertracker->ds[1], servermanager, &error);
	smlDsServerRegister(servertracker->ds[2], servermanager, &error);
	
	g_object_unref(loc1);
	g_object_unref(loc2);
	g_object_unref(loc3);
	
	/* The authenticator */
	SmlAuthenticator *auth = smlAuthNew(&error);
	smlAuthSetEnable(auth, FALSE);
	smlAuthRegister(auth, clientmanager, &error);
	
	/* The authenticator */
	SmlAuthenticator *auth2 = smlAuthNew(&error);
	smlAuthSetEnable(auth2, FALSE);
	smlAuthRegister(auth2, servermanager, &error);
	
	clienttracker->session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 0, 0, &error);
	
	sml_fail_unless(smlManagerSessionAdd(clientmanager, clienttracker->session, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	g_object_unref(loc);
	
	clienttracker->dssessions[0] = smlDsServerSendAlert(clienttracker->ds[0], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[1] = smlDsServerSendAlert(clienttracker->ds[1], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[2] = smlDsServerSendAlert(clienttracker->ds[2], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	while (init_alerts_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	smlDsSessionGetAlert(servertracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	smlDsSessionSendAlert(servertracker->dssessions[0], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[1], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[2], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetAlert(clienttracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	while (alerts_received < 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}

	const char *content_types[] = {SML_ELEMENT_TEXT_VCARD, SML_ELEMENT_TEXT_VCAL, SML_ELEMENT_TEXT_PLAIN};
	int k = 0;
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(clienttracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);
	
		unsigned int i = 0;
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(2), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(clienttracker->dssessions[k], &error);
	}

	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetSync(servertracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	
	while (syncs_received < 3 || adds_received < num_items * 3 || deletes_received < num_items * 3 || modifies_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionEnd(servertracker->session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSessionUnref(servertracker->session); /* unref for ref from callback */
	smlSessionUnref(clienttracker->session); /* unref for ref from callback */
	smlSessionUnref(clienttracker->session); /* unref for smlSessionNew */
	
	while (num_end < 2 || replies_received < 9 || num_finals < 4) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(init_alerts_received == 3, NULL);
	sml_fail_unless(alerts_received == 6, NULL);
	sml_fail_unless(syncs_received == 3, NULL);
	sml_fail_unless(sync_ends_received == 0, NULL);
	sml_fail_unless(changes_received == 0, NULL);
	sml_fail_unless(replies_received == 9, NULL);
	sml_fail_unless(adds_received == num_items * 3, NULL);
	sml_fail_unless(add_replies_received == num_items * 3, NULL);
	sml_fail_unless(deletes_received == num_items * 3, NULL);
	sml_fail_unless(delete_replies_received == num_items * 3, NULL);
	sml_fail_unless(modifies_received == num_items * 3, NULL);
	sml_fail_unless(modify_replies_received == num_items * 3, NULL);
	sml_fail_unless(transport_errors == 0, NULL);
	sml_fail_unless(num_sessions == 2, NULL);
	sml_fail_unless(num_finals == 4, NULL);
	sml_fail_unless(num_end == 2, NULL);
	sml_fail_unless(session_errors == 0, NULL);
	
	smlDsSessionUnref(clienttracker->dssessions[0]);
	smlDsSessionUnref(clienttracker->dssessions[1]);
	smlDsSessionUnref(clienttracker->dssessions[2]);
	
	smlDsSessionUnref(servertracker->dssessions[0]);
	smlDsSessionUnref(servertracker->dssessions[1]);
	smlDsSessionUnref(servertracker->dssessions[2]);
	
	smlDsServerFree(clienttracker->ds[0]);
	smlDsServerFree(clienttracker->ds[1]);
	smlDsServerFree(clienttracker->ds[2]);
	
	smlDsServerFree(servertracker->ds[0]);
	smlDsServerFree(servertracker->ds[1]);
	smlDsServerFree(servertracker->ds[2]);
	
	smlAuthFree(auth);
	smlAuthFree(auth2);
	
	g_free(clienttracker);
	g_free(servertracker);
	
	smlManagerStop(clientmanager);
	smlManagerStop(servermanager);
	
	while(num_disconnects < 2) {
		smlManagerDispatch(clientmanager);
		smlManagerDispatch(servermanager);
	}
	
	smlManagerFree(clientmanager);
	smlManagerFree(servermanager);
	
	sml_fail_unless(smlTransportFinalize(server, &error), NULL);
	sml_fail_unless(smlTransportFinalize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	
	smlTransportFree(server);
	smlTransportFree(client);
}
END_TEST

/* client -- 3 * alert ---> server
 * server -- statuses, 3 * alert ---> client
 * client -- statuses, num * add, num * replace, num * delete ---> server
 * server -- statuses, num * add, num * replace, num * delete  ---> client
 * client -- statuses, map ---> server
 * server -- statuses ---> client
 */
START_TEST (sync_multi_stress2)
{
	reset_testbed();

	unsigned int num_items = 100;
	num_changes = 3 * num_items;
	
	GError *error = NULL;

	SmlTransport *server = smlTransportNew(SML_TRANSPORT_HTTP_SERVER, &error);
	SmlTransport *client = smlTransportNew(SML_TRANSPORT_HTTP_CLIENT, &error);
		
	sml_fail_unless(smlTransportSetConfigOption(client, "URL", "http://127.0.0.1:12014", &error), NULL);

	sml_fail_unless(smlTransportSetConfigOption(server, "PORT", "12014", &error), NULL);
	
	managerTracker *clienttracker = g_malloc0(sizeof(managerTracker));
	SmlManager *clientmanager = clienttracker->manager = smlManagerNew(client, &error);
	smlManagerSetEventCallback(clienttracker->manager, _manager_event, clienttracker);
	managerTracker *servertracker = g_malloc0(sizeof(managerTracker));
	SmlManager *servermanager = servertracker->manager = smlManagerNew(server, &error);
	smlManagerSetEventCallback(servertracker->manager, _manager_event, servertracker);
	smlManagerSetLocalMaxMsgSize(servertracker->manager, TEST_DEFAULT_MAX_MSG_SIZE);
	smlManagerSetLocalMaxObjSize(servertracker->manager, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	sml_fail_unless(error == NULL, "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(server, &error), "%s", GET_ERROR_MESSAGE(error));

	sml_fail_unless(smlManagerStart(clientmanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlManagerStart(servermanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "test");
	
	SmlLocation *loc1 = sml_location_new();
	sml_fail_unless(loc1 != NULL, NULL);
	sml_location_set_uri(loc1, "test1");
	
	SmlLocation *loc2 = sml_location_new();
	sml_fail_unless(loc2 != NULL, NULL);
	sml_location_set_uri(loc2, "test2");
	
	SmlLocation *loc3 = sml_location_new();
	sml_fail_unless(loc3 != NULL, NULL);
	sml_location_set_uri(loc3, "test3");
	
	clienttracker->ds[0] = smlDsClientNew(SML_ELEMENT_TEXT_VCARD, loc1, loc1, &error);
	clienttracker->ds[1] = smlDsClientNew(SML_ELEMENT_TEXT_VCAL, loc2, loc2, &error);
	clienttracker->ds[2] = smlDsClientNew(SML_ELEMENT_TEXT_PLAIN, loc3, loc3, &error);
	smlDsServerRegister(clienttracker->ds[0], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[1], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[2], clientmanager, &error);
				
	servertracker->ds[0] = smlDsServerNew(SML_ELEMENT_TEXT_VCARD, loc1, &error);
	servertracker->ds[1] = smlDsServerNew(SML_ELEMENT_TEXT_VCAL, loc2, &error);
	servertracker->ds[2] = smlDsServerNew(SML_ELEMENT_TEXT_PLAIN, loc3, &error);
	smlDsServerSetConnectCallback(servertracker->ds[0], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[1], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[2], _recv_init_alert, servertracker);
	smlDsServerRegister(servertracker->ds[0], servermanager, &error);
	smlDsServerRegister(servertracker->ds[1], servermanager, &error);
	smlDsServerRegister(servertracker->ds[2], servermanager, &error);
	
	g_object_unref(loc1);
	g_object_unref(loc2);
	g_object_unref(loc3);
	
	/* The authenticator */
	SmlAuthenticator *auth = smlAuthNew(&error);
	smlAuthSetEnable(auth, FALSE);
	smlAuthRegister(auth, clientmanager, &error);
	
	/* The authenticator */
	SmlAuthenticator *auth2 = smlAuthNew(&error);
	smlAuthSetEnable(auth2, FALSE);
	smlAuthRegister(auth2, servermanager, &error);
	
	clienttracker->session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 0, 0, &error);
	
	sml_fail_unless(smlManagerSessionAdd(clientmanager, clienttracker->session, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	g_object_unref(loc);
	
	clienttracker->dssessions[0] = smlDsServerSendAlert(clienttracker->ds[0], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[1] = smlDsServerSendAlert(clienttracker->ds[1], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[2] = smlDsServerSendAlert(clienttracker->ds[2], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	while (init_alerts_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	smlDsSessionGetAlert(servertracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	smlDsSessionSendAlert(servertracker->dssessions[0], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[1], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[2], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetAlert(clienttracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	while (alerts_received < 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	const char *content_types[] = {SML_ELEMENT_TEXT_VCARD, SML_ELEMENT_TEXT_VCAL, SML_ELEMENT_TEXT_PLAIN};
	int k = 0;
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(clienttracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);
	
		unsigned int i = 0;
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(2), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(clienttracker->dssessions[k], &error);
	}
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetSync(servertracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetMapping(servertracker->dssessions[0], _recv_map, GINT_TO_POINTER(1));
	smlDsSessionGetMapping(servertracker->dssessions[1], _recv_map, GINT_TO_POINTER(1));
	smlDsSessionGetMapping(servertracker->dssessions[2], _recv_map, GINT_TO_POINTER(1));
	
	while (syncs_received < 3 || adds_received < num_items * 3 || deletes_received < num_items * 3 || modifies_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(servertracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);

		unsigned int i = 0;	
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(servertracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(servertracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(servertracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(servertracker->dssessions[k], &error);
	}
	
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetSync(clienttracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(clienttracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(clienttracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(clienttracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(clienttracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(clienttracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	
	while (syncs_received < 6 || adds_received < num_items * 6 || deletes_received < num_items * 6 || modifies_received < num_items * 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}

	unsigned int i = 0;	
	for (i = 0; i < num_items; i++) {
		SmlMapItem *item = sml_map_item_new();
		SmlLocation *local = sml_location_new();
		sml_fail_unless(local != NULL, NULL);
		sml_location_set_uri(local, "uid");
		sml_map_item_set_local(item, local, &error);
		g_object_unref(local);
		local = NULL;
		SmlLocation *remote = sml_location_new();
		sml_fail_unless(remote != NULL, NULL);
		sml_location_set_uri(remote, "newuid");
		sml_map_item_set_remote(item, remote, &error);
		g_object_unref(remote);
		remote = NULL;
		sml_fail_unless(smlDsSessionQueueMap(clienttracker->dssessions[0], item, &error), NULL);
		sml_fail_unless(smlDsSessionQueueMap(clienttracker->dssessions[1], item, &error), NULL);
		sml_fail_unless(smlDsSessionQueueMap(clienttracker->dssessions[2], item, &error), NULL);
	}
	
	smlDsSessionCloseMap(clienttracker->dssessions[0], _map_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionCloseMap(clienttracker->dssessions[1], _map_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionCloseMap(clienttracker->dssessions[2], _map_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	
	while (delete_replies_received < num_items * 6 || mappings_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionEnd(servertracker->session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSessionUnref(servertracker->session); /* unref for event SESSION_NEW */
	smlSessionUnref(clienttracker->session); /* unref for event SESSION_NEW */
	smlSessionUnref(clienttracker->session); /* unref for smlSessionNew */
	
	while (num_end < 2 || replies_received < 12 || num_finals < 6) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(init_alerts_received == 3, NULL);
	sml_fail_unless(alerts_received == 6, NULL);
	sml_fail_unless(syncs_received == 6, NULL);
	sml_fail_unless(sync_ends_received == 0, NULL);
	sml_fail_unless(changes_received == 0, NULL);
	sml_fail_unless(replies_received == 12, NULL);
	sml_fail_unless(adds_received == num_items * 6, NULL);
	sml_fail_unless(add_replies_received == num_items * 6, NULL);
	sml_fail_unless(deletes_received == num_items * 6, NULL);
	sml_fail_unless(delete_replies_received == num_items * 6, NULL);
	sml_fail_unless(modifies_received == num_items * 6, NULL);
	sml_fail_unless(modify_replies_received == num_items * 6, NULL);
	sml_fail_unless(mappings_received == num_items * 3, NULL);
	sml_fail_unless(transport_errors == 0, NULL);
	sml_fail_unless(num_sessions == 2, NULL);
	sml_fail_unless(num_finals == 6, NULL);
	sml_fail_unless(num_end == 2, NULL);
	sml_fail_unless(session_errors == 0, NULL);
	
	smlDsSessionUnref(clienttracker->dssessions[0]);
	smlDsSessionUnref(clienttracker->dssessions[1]);
	smlDsSessionUnref(clienttracker->dssessions[2]);
	
	smlDsSessionUnref(servertracker->dssessions[0]);
	smlDsSessionUnref(servertracker->dssessions[1]);
	smlDsSessionUnref(servertracker->dssessions[2]);
	
	smlDsServerFree(clienttracker->ds[0]);
	smlDsServerFree(clienttracker->ds[1]);
	smlDsServerFree(clienttracker->ds[2]);
	
	smlDsServerFree(servertracker->ds[0]);
	smlDsServerFree(servertracker->ds[1]);
	smlDsServerFree(servertracker->ds[2]);
	
	smlAuthFree(auth);
	smlAuthFree(auth2);
	
	g_free(clienttracker);
	g_free(servertracker);
	
	smlManagerStop(clientmanager);
	smlManagerStop(servermanager);
	
	while(num_disconnects < 2) {
		smlManagerDispatch(clientmanager);
		smlManagerDispatch(servermanager);
	}
	
	smlManagerFree(clientmanager);
	smlManagerFree(servermanager);
	
	sml_fail_unless(smlTransportFinalize(server, &error), NULL);
	sml_fail_unless(smlTransportFinalize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	
	smlTransportFree(server);
	smlTransportFree(client);
}
END_TEST

/* client -- 3 * alert ---> server
 * server -- statuses, 3 * alert ---> client
 * client -- statuses, num * add, num * replace, num * delete ---> server
 * server -- statuses ---> client
 */
START_TEST (sync_multi_conf_from_devinf)
{
	reset_testbed();

	unsigned int num_items = 100;
	num_changes = 3 * num_items;

	GError *error = NULL;

	SmlTransport *server = smlTransportNew(SML_TRANSPORT_HTTP_SERVER, &error);
	SmlTransport *client = smlTransportNew(SML_TRANSPORT_HTTP_CLIENT, &error);
	
	sml_fail_unless(smlTransportSetConfigOption(client, "URL", "http://127.0.0.1:12015", &error), NULL);

	sml_fail_unless(smlTransportSetConfigOption(server, "PORT", "12015", &error), NULL);
	
	managerTracker *clienttracker = g_malloc0(sizeof(managerTracker));
	SmlManager *clientmanager = clienttracker->manager = smlManagerNew(client, &error);
	smlManagerSetEventCallback(clienttracker->manager, _manager_event, clienttracker);
	managerTracker *servertracker = g_malloc0(sizeof(managerTracker));
	SmlManager *servermanager = servertracker->manager = smlManagerNew(server, &error);
	smlManagerSetEventCallback(servertracker->manager, _manager_event, servertracker);
	smlManagerSetLocalMaxMsgSize(servertracker->manager, TEST_DEFAULT_MAX_MSG_SIZE);
	smlManagerSetLocalMaxObjSize(servertracker->manager, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	sml_fail_unless(error == NULL, "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(server, &error), "%s", GET_ERROR_MESSAGE(error));

	sml_fail_unless(smlManagerStart(clientmanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlManagerStart(servermanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "test");
	
	SmlLocation *loc1 = sml_location_new();
	sml_fail_unless(loc1 != NULL, NULL);
	sml_location_set_uri(loc1, "test1");
	
	SmlLocation *loc2 = sml_location_new();
	sml_fail_unless(loc2 != NULL, NULL);
	sml_location_set_uri(loc2, "test2");
	
	SmlLocation *loc3 = sml_location_new();
	sml_fail_unless(loc3 != NULL, NULL);
	sml_location_set_uri(loc3, "test3");
	
	clienttracker->ds[0] = smlDsClientNew(SML_ELEMENT_TEXT_VCARD, loc1, loc1, &error);
	clienttracker->ds[1] = smlDsClientNew(SML_ELEMENT_TEXT_VCAL, loc2, loc2, &error);
	clienttracker->ds[2] = smlDsClientNew(SML_ELEMENT_TEXT_PLAIN, loc3, loc3, &error);
	smlDsServerRegister(clienttracker->ds[0], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[1], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[2], clientmanager, &error);
				
	servertracker->ds[0] = smlDsServerNew(SML_ELEMENT_TEXT_VCARD, loc1, &error);
	servertracker->ds[1] = smlDsServerNew(SML_ELEMENT_TEXT_VCAL, loc2, &error);
	servertracker->ds[2] = smlDsServerNew(SML_ELEMENT_TEXT_PLAIN, loc3, &error);
	smlDsServerSetConnectCallback(servertracker->ds[0], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[1], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[2], _recv_init_alert, servertracker);
	smlDsServerRegister(servertracker->ds[0], servermanager, &error);
	smlDsServerRegister(servertracker->ds[1], servermanager, &error);
	smlDsServerRegister(servertracker->ds[2], servermanager, &error);
	
	/* The devinf obj */
	SmlDevInf *devinf = sml_dev_inf_new();
	sml_fail_unless(devinf != NULL, NULL);
	sml_dev_inf_set_dev_typ(devinf, SML_DEVINF_DEVTYP_WORKSTATION);
	sml_fail_unless(sml_dev_inf_set_dev_id(devinf, "LibSyncML", &error), "%s", error?error->message:"No GError set.");
	sml_dev_inf_set_support_number_of_changes(devinf, TRUE);
	sml_dev_inf_set_support_large_objs(devinf, FALSE);
	sml_dev_inf_set_support_utc(devinf, FALSE);
	SmlDevInfAgent *clientagent = smlDevInfAgentNew(devinf, &error);
	smlDevInfAgentRegister(clientagent, clientmanager, &error);

	/* And we also add the devinfo to the devinf agent */
	SmlDevInfDataStore *datastore = sml_dev_inf_data_store_new(sml_location_get_uri(loc1), &error);
	_SET_DATASTORE_RX_PREF(SML_ELEMENT_TEXT_VCARD, "2.1");
	_SET_DATASTORE_TX_PREF(SML_ELEMENT_TEXT_VCARD, "2.1");
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE);
	sml_fail_unless(sml_dev_inf_add_data_store(devinf, datastore, &error), "%s", error?error->message:"No GError set.");
	
	datastore = sml_dev_inf_data_store_new(sml_location_get_uri(loc2), &error);
	_SET_DATASTORE_RX_PREF(SML_ELEMENT_TEXT_VCAL, "2.0");
	_SET_DATASTORE_TX_PREF(SML_ELEMENT_TEXT_VCAL, "2.0");
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE);
	sml_fail_unless(sml_dev_inf_add_data_store(devinf, datastore, &error), "%s", error?error->message:"No GError set.");
	
	datastore = sml_dev_inf_data_store_new(sml_location_get_uri(loc3), &error);
	_SET_DATASTORE_RX_PREF(SML_ELEMENT_TEXT_PLAIN, "1.0");
	_SET_DATASTORE_TX_PREF(SML_ELEMENT_TEXT_PLAIN, "1.0");
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE);
	sml_fail_unless(sml_dev_inf_add_data_store(devinf, datastore, &error), "%s", error?error->message:"No GError set.");
	
	devinf = sml_dev_inf_new();
	sml_fail_unless(devinf != NULL, NULL);
	sml_dev_inf_set_dev_typ(devinf, SML_DEVINF_DEVTYP_SERVER);
	sml_fail_unless(sml_dev_inf_set_dev_id(devinf, "LibSyncML", &error), "%s", error?error->message:"No GError set.");
	sml_dev_inf_set_support_number_of_changes(devinf, TRUE);
	sml_dev_inf_set_support_large_objs(devinf, TRUE);
	sml_dev_inf_set_support_utc(devinf, FALSE);
	SmlDevInfAgent *serveragent = smlDevInfAgentNew(devinf, &error);
	smlDevInfAgentRegister(serveragent, servermanager, &error);
	
	datastore = sml_dev_inf_data_store_new(sml_location_get_uri(loc1), &error);
	_SET_DATASTORE_RX_PREF(SML_ELEMENT_TEXT_VCARD, "2.1");
	_SET_DATASTORE_TX_PREF(SML_ELEMENT_TEXT_VCARD, "2.1");
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE);
	sml_fail_unless(sml_dev_inf_add_data_store(devinf, datastore, &error), "%s", error?error->message:"No GError set.");
	
	datastore = sml_dev_inf_data_store_new(sml_location_get_uri(loc2), &error);
	_SET_DATASTORE_RX_PREF(SML_ELEMENT_TEXT_VCAL, "2.0");
	_SET_DATASTORE_TX_PREF(SML_ELEMENT_TEXT_VCAL, "2.0");
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE);
	sml_fail_unless(sml_dev_inf_add_data_store(devinf, datastore, &error), "%s", error?error->message:"No GError set.");
	
	datastore = sml_dev_inf_data_store_new(sml_location_get_uri(loc3), &error);
	_SET_DATASTORE_RX_PREF(SML_ELEMENT_TEXT_PLAIN, "1.0");
	_SET_DATASTORE_TX_PREF(SML_ELEMENT_TEXT_PLAIN, "1.0");
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC, TRUE);
	sml_dev_inf_data_store_set_sync_cap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC, TRUE);
	sml_fail_unless(sml_dev_inf_add_data_store(devinf, datastore, &error), "%s", error?error->message:"No GError set.");
	
	g_object_unref(loc1);
	g_object_unref(loc2);
	g_object_unref(loc3);
	
	/* The authenticator */
	SmlAuthenticator *auth = smlAuthNew(&error);
	smlAuthSetEnable(auth, FALSE);
	smlAuthRegister(auth, clientmanager, &error);
	
	/* The authenticator */
	SmlAuthenticator *auth2 = smlAuthNew(&error);
	smlAuthSetEnable(auth2, FALSE);
	smlAuthRegister(auth2, servermanager, &error);
	
	clienttracker->session = smlSessionNew(SML_SESSION_TYPE_CLIENT, SML_MIMETYPE_XML, SML_VERSION_12, SML_PROTOCOL_SYNCML, loc, loc, 0, 0, &error);
	smlSessionSetLocalMaxMsgSize(clienttracker->session, TEST_DEFAULT_MAX_MSG_SIZE);
	sml_fail_unless(smlSessionGetRemoteMaxObjSize(clienttracker->session) == 0, NULL);
	smlSessionSetLocalMaxObjSize(clienttracker->session, TEST_DEFAULT_MAX_OBJ_SIZE);
	sml_fail_unless(smlSessionGetLocalMaxObjSize(clienttracker->session) == TEST_DEFAULT_MAX_OBJ_SIZE, NULL);
	
	if (!sml_dev_inf_get_support_number_of_changes(devinf))
		smlSessionUseNumberOfChanges(clienttracker->session, FALSE);
	if (!sml_dev_inf_get_support_large_objs(devinf))
		smlSessionUseLargeObjects(clienttracker->session, FALSE);
		
	sml_fail_unless(smlManagerSessionAdd(clientmanager, clienttracker->session, NULL, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	g_object_unref(loc);
	
	clienttracker->dssessions[0] = smlDsServerSendAlert(clienttracker->ds[0], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[1] = smlDsServerSendAlert(clienttracker->ds[1], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[2] = smlDsServerSendAlert(clienttracker->ds[2], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlDevInfAgentSendDevInf(clientagent, clienttracker->session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	while (init_alerts_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(smlSessionGetRemoteMaxMsgSize(servertracker->session) == TEST_DEFAULT_MAX_MSG_SIZE, NULL);
	sml_fail_unless(smlSessionGetRemoteMaxObjSize(servertracker->session) == TEST_DEFAULT_MAX_OBJ_SIZE, "%u", smlSessionGetRemoteMaxObjSize(servertracker->session));
	smlSessionSetLocalMaxMsgSize(servertracker->session, TEST_DEFAULT_MAX_MSG_SIZE);
	smlSessionSetLocalMaxObjSize(servertracker->session, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	smlDsSessionGetAlert(servertracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	while (alerts_received < 3 || !smlDevInfAgentGetSessionDevInf(serveragent, servertracker->session)) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	SmlDevInf *recvClientDevInf = smlDevInfAgentGetSessionDevInf(serveragent, servertracker->session);
	sml_fail_unless(recvClientDevInf != NULL, NULL);
	sml_fail_unless(sml_dev_inf_num_data_stores(recvClientDevInf) == 3, NULL);
	sml_fail_unless(sml_dev_inf_get_support_number_of_changes(recvClientDevInf) == TRUE, NULL);
	sml_fail_unless(sml_dev_inf_get_support_large_objs(recvClientDevInf) == FALSE, NULL);
	sml_fail_unless(sml_dev_inf_get_support_utc(recvClientDevInf) == FALSE, NULL);
	
	sml_fail_unless(smlDevInfAgentSendDevInf(serveragent, servertracker->session, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(error == NULL, "%s", GET_ERROR_MESSAGE(error));
	
	smlDsSessionSendAlert(servertracker->dssessions[0], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[1], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[2], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetAlert(clienttracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	while (alerts_received < 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(smlSessionGetRemoteMaxMsgSize(clienttracker->session) == TEST_DEFAULT_MAX_MSG_SIZE, NULL);
	sml_fail_unless(smlSessionGetRemoteMaxObjSize(servertracker->session) == TEST_DEFAULT_MAX_OBJ_SIZE, NULL);
	
	SmlDevInf *recvServerDevInf = smlDevInfAgentGetSessionDevInf(clientagent, clienttracker->session);
	sml_fail_unless(recvServerDevInf != NULL, NULL);
	sml_fail_unless(sml_dev_inf_num_data_stores(recvServerDevInf) == 3, NULL);
	sml_fail_unless(sml_dev_inf_get_support_number_of_changes(recvServerDevInf) == TRUE, NULL);
	sml_fail_unless(sml_dev_inf_get_support_large_objs(recvServerDevInf) == TRUE, NULL);
	sml_fail_unless(sml_dev_inf_get_support_utc(recvServerDevInf) == FALSE, NULL);
	
	const char *content_types[] = {SML_ELEMENT_TEXT_VCARD, SML_ELEMENT_TEXT_VCAL, SML_ELEMENT_TEXT_PLAIN};
	int k = 0;
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(clienttracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);
	
		unsigned int i = 0;
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(2), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(clienttracker->dssessions[k], &error);
	}
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetSync(servertracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetMapping(servertracker->dssessions[0], _recv_map, GINT_TO_POINTER(1));
	smlDsSessionGetMapping(servertracker->dssessions[1], _recv_map, GINT_TO_POINTER(1));
	smlDsSessionGetMapping(servertracker->dssessions[2], _recv_map, GINT_TO_POINTER(1));
	
	while (syncs_received < 3 || adds_received < num_items * 3 || deletes_received < num_items * 3 || modifies_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(servertracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);

		unsigned int i = 0;	
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(servertracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(servertracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(servertracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(servertracker->dssessions[k], &error);
	}
	
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetSync(clienttracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(clienttracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(clienttracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(clienttracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(clienttracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(clienttracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	
	while (syncs_received < 6 || adds_received < num_items * 6 || deletes_received < num_items * 6 || modifies_received < num_items * 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}

	unsigned int i = 0;	
	for (i = 0; i < num_items; i++) {
		SmlMapItem *item = sml_map_item_new();
		SmlLocation *local = sml_location_new();
		sml_fail_unless(local != NULL, NULL);
		sml_location_set_uri(local, "uid");
		sml_map_item_set_local(item, local, &error);
		g_object_unref(local);
		local = NULL;
		SmlLocation *remote = sml_location_new();
		sml_fail_unless(remote != NULL, NULL);
		sml_location_set_uri(remote, "newuid");
		sml_map_item_set_remote(item, remote, &error);
		g_object_unref(remote);
		remote = NULL;
		sml_fail_unless(smlDsSessionQueueMap(clienttracker->dssessions[0], item, &error), NULL);
		sml_fail_unless(smlDsSessionQueueMap(clienttracker->dssessions[1], item, &error), NULL);
		sml_fail_unless(smlDsSessionQueueMap(clienttracker->dssessions[2], item, &error), NULL);
	}
	
	smlDsSessionCloseMap(clienttracker->dssessions[0], _map_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionCloseMap(clienttracker->dssessions[1], _map_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionCloseMap(clienttracker->dssessions[2], _map_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	
	while (delete_replies_received < num_items * 6 || mappings_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	
	sml_fail_unless(smlSessionGetRemoteMaxMsgSize(servertracker->session) == TEST_DEFAULT_MAX_MSG_SIZE, NULL);
	sml_fail_unless(smlSessionGetRemoteMaxObjSize(servertracker->session) == TEST_DEFAULT_MAX_OBJ_SIZE, NULL);
	
	sml_fail_unless(smlSessionGetRemoteMaxMsgSize(clienttracker->session) == TEST_DEFAULT_MAX_MSG_SIZE, NULL);
	sml_fail_unless(smlSessionGetRemoteMaxObjSize(clienttracker->session) == TEST_DEFAULT_MAX_OBJ_SIZE, NULL);
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionEnd(servertracker->session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSessionUnref(servertracker->session); /* unref from ref at callback */
	smlSessionUnref(clienttracker->session); /* unref from ref at callback */
	smlSessionUnref(clienttracker->session); /* unref from smlSessionNew */
	
	while (num_end < 2 || replies_received < 12 || num_finals < 6) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(init_alerts_received == 3, NULL);
	sml_fail_unless(alerts_received == 6, NULL);
	sml_fail_unless(syncs_received == 6, NULL);
	sml_fail_unless(sync_ends_received == 0, NULL);
	sml_fail_unless(changes_received == 0, NULL);
	sml_fail_unless(replies_received == 12, NULL);
	sml_fail_unless(adds_received == num_items * 6, NULL);
	sml_fail_unless(add_replies_received == num_items * 6, NULL);
	sml_fail_unless(deletes_received == num_items * 6, NULL);
	sml_fail_unless(delete_replies_received == num_items * 6, NULL);
	sml_fail_unless(modifies_received == num_items * 6, NULL);
	sml_fail_unless(modify_replies_received == num_items * 6, NULL);
	sml_fail_unless(mappings_received == num_items * 3, NULL);
	sml_fail_unless(transport_errors == 0, NULL);
	sml_fail_unless(num_sessions == 2, NULL);
	sml_fail_unless(num_finals == 6, NULL);
	sml_fail_unless(num_end == 2, NULL);
	sml_fail_unless(session_errors == 0, NULL);
	
	
	smlDsSessionUnref(clienttracker->dssessions[0]);
	smlDsSessionUnref(clienttracker->dssessions[1]);
	smlDsSessionUnref(clienttracker->dssessions[2]);
	
	smlDsSessionUnref(servertracker->dssessions[0]);
	smlDsSessionUnref(servertracker->dssessions[1]);
	smlDsSessionUnref(servertracker->dssessions[2]);
	
	smlDsServerFree(clienttracker->ds[0]);
	smlDsServerFree(clienttracker->ds[1]);
	smlDsServerFree(clienttracker->ds[2]);
	
	smlDsServerFree(servertracker->ds[0]);
	smlDsServerFree(servertracker->ds[1]);
	smlDsServerFree(servertracker->ds[2]);
	
	smlAuthFree(auth);
	smlAuthFree(auth2);
	
	g_free(clienttracker);
	g_free(servertracker);
	
	smlManagerStop(clientmanager);
	smlManagerStop(servermanager);
	
	while(num_disconnects < 2) {
		smlManagerDispatch(clientmanager);
		smlManagerDispatch(servermanager);
	}
	
	smlManagerFree(clientmanager);
	smlManagerFree(servermanager);
	
	sml_fail_unless(smlTransportFinalize(server, &error), NULL);
	sml_fail_unless(smlTransportFinalize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	
	smlTransportFree(server);
	smlTransportFree(client);

	smlDevInfAgentFree(clientagent);
	smlDevInfAgentFree(serveragent);
}
END_TEST

#ifdef ENABLE_OBEX
#ifdef ENABLE_OPENOBEX_TCP
START_TEST (sync_send_san)
{
	reset_testbed();

	unsigned int num_items = 10;
	num_changes = 3 * num_items;
	
	GError *error = NULL;
	
	/* The OMA DS client is an OBEX server. */
	SmlTransport *client = smlTransportNew(SML_TRANSPORT_OBEX_SERVER, &error);
	sml_fail_unless(smlTransportSetConnectionType(client, SML_TRANSPORT_CONNECTION_TYPE_NET, &error), NULL);
	sml_fail_unless(smlTransportSetConfigOption(client, "PORT", "12010", &error), "%s", GET_ERROR_MESSAGE(error));

	/* The OMA DS server is an OBEX client. */
	SmlTransport *server = smlTransportNew(SML_TRANSPORT_OBEX_CLIENT, &error);
	sml_fail_unless(smlTransportSetConnectionType(server, SML_TRANSPORT_CONNECTION_TYPE_NET, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportSetConfigOption(server, "PORT", "12010", &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportSetConfigOption(server, "URL", "127.0.0.1", &error), "%s", GET_ERROR_MESSAGE(error));
	
	managerTracker *clienttracker = g_malloc0(sizeof(managerTracker));
	SmlManager *clientmanager = clienttracker->manager = smlManagerNew(client, &error);
	smlManagerSetEventCallback(clienttracker->manager, _manager_event, clienttracker);
	managerTracker *servertracker = g_malloc0(sizeof(managerTracker));
	SmlManager *servermanager = servertracker->manager = smlManagerNew(server, &error);
	smlManagerSetEventCallback(servertracker->manager, _manager_event, servertracker);
	smlManagerSetLocalMaxMsgSize(servertracker->manager, TEST_DEFAULT_MAX_MSG_SIZE);
	smlManagerSetLocalMaxObjSize(servertracker->manager, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	sml_fail_unless(smlManagerStart(clientmanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlManagerStart(servermanager, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(smlTransportInitialize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(server, &error), "%s", GET_ERROR_MESSAGE(error));

	SmlLocation *loc = sml_location_new();
	sml_fail_unless(loc != NULL, NULL);
	sml_location_set_uri(loc, "test");
	
	SmlLocation *loc1 = sml_location_new();
	sml_fail_unless(loc1 != NULL, NULL);
	sml_location_set_uri(loc1, "test1");
	
	SmlLocation *loc2 = sml_location_new();
	sml_fail_unless(loc2 != NULL, NULL);
	sml_location_set_uri(loc2, "test2");
	
	SmlLocation *loc3 = sml_location_new();
	sml_fail_unless(loc3 != NULL, NULL);
	sml_location_set_uri(loc3, "test3");
	
	clienttracker->ds[0] = smlDsClientNew(SML_ELEMENT_TEXT_VCARD, loc1, loc1, &error);
	clienttracker->ds[1] = smlDsClientNew(SML_ELEMENT_TEXT_VCAL, loc2, loc2, &error);
	clienttracker->ds[2] = smlDsClientNew(SML_ELEMENT_TEXT_PLAIN, loc3, loc3, &error);
	smlDsServerSetSanSessionCallback(clienttracker->ds[0], _recv_san, GINT_TO_POINTER(1));
	smlDsServerSetSanSessionCallback(clienttracker->ds[1], _recv_san, GINT_TO_POINTER(1));
	smlDsServerSetSanSessionCallback(clienttracker->ds[2], _recv_san, GINT_TO_POINTER(1));
	smlDsServerRegister(clienttracker->ds[0], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[1], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[2], clientmanager, &error);
				
	servertracker->ds[0] = smlDsServerNew(SML_ELEMENT_TEXT_VCARD, loc1, &error);
	servertracker->ds[1] = smlDsServerNew(SML_ELEMENT_TEXT_VCAL, loc2, &error);
	servertracker->ds[2] = smlDsServerNew(SML_ELEMENT_TEXT_PLAIN, loc3, &error);
	smlDsServerSetConnectCallback(servertracker->ds[0], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[1], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[2], _recv_init_alert, servertracker);
	smlDsServerRegister(servertracker->ds[0], servermanager, &error);
	smlDsServerRegister(servertracker->ds[1], servermanager, &error);
	smlDsServerRegister(servertracker->ds[2], servermanager, &error);
	
	g_object_unref(loc1);
	g_object_unref(loc2);
	g_object_unref(loc3);
	
	/* The authenticator */
	SmlAuthenticator *auth = smlAuthNew(&error);
	smlAuthSetEnable(auth, FALSE);
	smlAuthRegister(auth, clientmanager, &error);
	
	/* The authenticator */
	SmlAuthenticator *auth2 = smlAuthNew(&error);
	smlAuthSetEnable(auth2, FALSE);
	smlAuthRegister(auth2, servermanager, &error);
	
	sml_fail_unless(smlTransportConnect(server, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlNotification *san = smlNotificationNew(SML_SAN_VERSION_11, SML_SAN_UIMODE_USER, SML_SAN_INITIATOR_SERVER, 65535, "test", "/", SML_MIMETYPE_XML, &error);
	sml_fail_unless(san != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlNotificationSetManager(san, servermanager);
	
	sml_fail_unless(smlDsServerAddSan(servertracker->ds[0], san, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlDsServerAddSan(servertracker->ds[1], san, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlDsServerAddSan(servertracker->ds[2], san, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	sml_fail_unless(smlNotificationSend(san, server, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	smlNotificationFree(san);
	
	while (sans_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(clienttracker->session != NULL, NULL);
	
	g_object_unref(loc);
	
	clienttracker->dssessions[0] = smlDsServerSendAlert(clienttracker->ds[0], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[1] = smlDsServerSendAlert(clienttracker->ds[1], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[2] = smlDsServerSendAlert(clienttracker->ds[2], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	while (init_alerts_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	smlDsSessionGetAlert(servertracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	smlDsSessionSendAlert(servertracker->dssessions[0], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[1], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[2], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetAlert(clienttracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	while (alerts_received < 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	const char *content_types[] = {SML_ELEMENT_TEXT_VCARD, SML_ELEMENT_TEXT_VCAL, SML_ELEMENT_TEXT_PLAIN};
	int k = 0;
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(clienttracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);
	
		unsigned int i = 0;
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(2), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(clienttracker->dssessions[k], &error);
	}
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetSync(servertracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	
	while (syncs_received < 3 || adds_received < num_items * 3 || deletes_received < num_items * 3 || modifies_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionEnd(servertracker->session, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	smlSessionUnref(servertracker->session);
	smlSessionUnref(clienttracker->session);
	
	while (num_end < 2 || replies_received < 9 || num_finals < 5) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(init_alerts_received == 3, NULL);
	sml_fail_unless(alerts_received == 6, NULL);
	sml_fail_unless(syncs_received == 3, NULL);
	sml_fail_unless(sync_ends_received == 0, NULL);
	sml_fail_unless(changes_received == 0, NULL);
	sml_fail_unless(replies_received == 9, NULL);
	sml_fail_unless(adds_received == num_items * 3, NULL);
	sml_fail_unless(add_replies_received == num_items * 3, NULL);
	sml_fail_unless(deletes_received == num_items * 3, NULL);
	sml_fail_unless(delete_replies_received == num_items * 3, NULL);
	sml_fail_unless(modifies_received == num_items * 3, NULL);
	sml_fail_unless(modify_replies_received == num_items * 3, NULL);
	sml_fail_unless(transport_errors == 0, NULL);
	sml_fail_unless(num_sessions == 2, NULL);
	sml_fail_unless(num_finals == 5, NULL);
	sml_fail_unless(num_end == 2, NULL);
	sml_fail_unless(session_errors == 0, NULL);
	
	
	smlDsSessionUnref(clienttracker->dssessions[0]);
	smlDsSessionUnref(clienttracker->dssessions[1]);
	smlDsSessionUnref(clienttracker->dssessions[2]);
	
	smlDsSessionUnref(servertracker->dssessions[0]);
	smlDsSessionUnref(servertracker->dssessions[1]);
	smlDsSessionUnref(servertracker->dssessions[2]);
	
	smlDsServerFree(clienttracker->ds[0]);
	smlDsServerFree(clienttracker->ds[1]);
	smlDsServerFree(clienttracker->ds[2]);
	
	smlDsServerFree(servertracker->ds[0]);
	smlDsServerFree(servertracker->ds[1]);
	smlDsServerFree(servertracker->ds[2]);
	
	smlAuthFree(auth);
	smlAuthFree(auth2);
	
	g_free(clienttracker);
	g_free(servertracker);
	
	/* first we have to stop the OBEX client or we get errors */

	smlManagerStop(servermanager);
	while(num_disconnects < 1) {
		smlManagerDispatch(servermanager);
	}
	smlManagerStop(clientmanager);
	while(num_disconnects < 2) {
		smlManagerDispatch(clientmanager);
	}
	
	smlManagerFree(clientmanager);
	smlManagerFree(servermanager);
	
	sml_fail_unless(smlTransportFinalize(server, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportFinalize(client, &error), NULL);
	
	smlTransportFree(server);
	smlTransportFree(client);
}
END_TEST
#endif
#endif

#ifdef ENABLE_OBEX
#ifdef ENABLE_OPENOBEX_TCP
START_TEST (sync_send_san12)
{
	reset_testbed();

	unsigned int num_items = 10;
	num_changes = 3 * num_items;
	
	GError *error = NULL;

	SmlTransport *server = smlTransportNew(SML_TRANSPORT_OBEX_CLIENT, &error);
	SmlTransport *client = smlTransportNew(SML_TRANSPORT_OBEX_SERVER, &error);
	
	sml_fail_unless(smlTransportSetConfigOption(client, "PORT", "12011", &error), NULL);
	sml_fail_unless(smlTransportSetConnectionType(client, SML_TRANSPORT_CONNECTION_TYPE_NET, &error), NULL);

	sml_fail_unless(smlTransportSetConfigOption(server, "URL", "127.0.0.1", &error), NULL);
	sml_fail_unless(smlTransportSetConfigOption(server, "PORT", "12011", &error), NULL);
	sml_fail_unless(smlTransportSetConnectionType(server, SML_TRANSPORT_CONNECTION_TYPE_NET, &error), NULL);
	
	managerTracker *clienttracker = g_malloc0(sizeof(managerTracker));
	SmlManager *clientmanager = clienttracker->manager = smlManagerNew(client, &error);
	smlManagerSetEventCallback(clienttracker->manager, _manager_event, clienttracker);
	managerTracker *servertracker = g_malloc0(sizeof(managerTracker));
	SmlManager *servermanager = servertracker->manager = smlManagerNew(server, &error);
	smlManagerSetEventCallback(servertracker->manager, _manager_event, servertracker);
	smlManagerSetLocalMaxMsgSize(servertracker->manager, TEST_DEFAULT_MAX_MSG_SIZE);
	smlManagerSetLocalMaxObjSize(servertracker->manager, TEST_DEFAULT_MAX_OBJ_SIZE);
	
	sml_fail_unless(smlManagerStart(clientmanager, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlManagerStart(servermanager, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(smlTransportInitialize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportInitialize(server, &error), "%s", GET_ERROR_MESSAGE(error));

	SmlLocation *loc1 = sml_location_new();
	sml_fail_unless(loc1 != NULL, NULL);
	sml_location_set_uri(loc1, "test1");
	
	SmlLocation *loc2 = sml_location_new();
	sml_fail_unless(loc2 != NULL, NULL);
	sml_location_set_uri(loc2, "test2");
	
	SmlLocation *loc3 = sml_location_new();
	sml_fail_unless(loc3 != NULL, NULL);
	sml_location_set_uri(loc3, "test3");
	
	clienttracker->ds[0] = smlDsClientNew(SML_ELEMENT_TEXT_VCARD, loc1, loc1, &error);
	clienttracker->ds[1] = smlDsClientNew(SML_ELEMENT_TEXT_VCAL, loc2, loc2, &error);
	clienttracker->ds[2] = smlDsClientNew(SML_ELEMENT_TEXT_PLAIN, loc3, loc3, &error);
	smlDsServerSetSanSessionCallback(clienttracker->ds[0], _recv_san, GINT_TO_POINTER(1));
	smlDsServerSetSanSessionCallback(clienttracker->ds[1], _recv_san, GINT_TO_POINTER(1));
	smlDsServerSetSanSessionCallback(clienttracker->ds[2], _recv_san, GINT_TO_POINTER(1));
	smlDsServerRegister(clienttracker->ds[0], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[1], clientmanager, &error);
	smlDsServerRegister(clienttracker->ds[2], clientmanager, &error);
				
	servertracker->ds[0] = smlDsServerNew(SML_ELEMENT_TEXT_VCARD, loc1, &error);
	servertracker->ds[1] = smlDsServerNew(SML_ELEMENT_TEXT_VCAL, loc2, &error);
	servertracker->ds[2] = smlDsServerNew(SML_ELEMENT_TEXT_PLAIN, loc3, &error);
	smlDsServerSetConnectCallback(servertracker->ds[0], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[1], _recv_init_alert, servertracker);
	smlDsServerSetConnectCallback(servertracker->ds[2], _recv_init_alert, servertracker);
	smlDsServerRegister(servertracker->ds[0], servermanager, &error);
	smlDsServerRegister(servertracker->ds[1], servermanager, &error);
	smlDsServerRegister(servertracker->ds[2], servermanager, &error);
	
	g_object_unref(loc1);
	g_object_unref(loc2);
	g_object_unref(loc3);
	
	/* The authenticator */
	SmlAuthenticator *auth = smlAuthNew(&error);
	smlAuthSetEnable(auth, FALSE);
	smlAuthRegister(auth, clientmanager, &error);
	
	/* The authenticator */
	SmlAuthenticator *auth2 = smlAuthNew(&error);
	smlAuthSetEnable(auth2, FALSE);
	smlAuthRegister(auth2, servermanager, &error);
	
	sml_fail_unless(smlTransportConnect(server, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	SmlNotification *san = smlNotificationNew(SML_SAN_VERSION_12, SML_SAN_UIMODE_USER, SML_SAN_INITIATOR_SERVER, 65535, "test", "/", SML_MIMETYPE_XML, &error);
	sml_fail_unless(san != NULL, NULL);
	sml_fail_unless(error == NULL, NULL);
	smlNotificationSetManager(san, servermanager);
	
	sml_fail_unless(smlDsServerAddSan(servertracker->ds[0], san, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlDsServerAddSan(servertracker->ds[1], san, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	sml_fail_unless(smlDsServerAddSan(servertracker->ds[2], san, &error), NULL);
	sml_fail_unless(error == NULL, NULL);

	sml_fail_unless(smlNotificationSend(san, server, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(error == NULL, "%s", GET_ERROR_MESSAGE(error));
	
	smlNotificationFree(san);
	
	while (sans_received < 3 || num_sessions < 1) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(clienttracker->session != NULL, NULL);
	
	clienttracker->dssessions[0] = smlDsServerSendAlert(clienttracker->ds[0], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[1] = smlDsServerSendAlert(clienttracker->ds[1], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	clienttracker->dssessions[2] = smlDsServerSendAlert(clienttracker->ds[2], clienttracker->session, SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), NULL);
	sml_fail_unless(error == NULL, NULL);
	
	while (init_alerts_received < 3 || num_sessions < 2) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	smlDsSessionGetAlert(servertracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(servertracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	smlDsSessionSendAlert(servertracker->dssessions[0], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[1], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	smlDsSessionSendAlert(servertracker->dssessions[2], SML_ALERT_TWO_WAY, "last", "next", _alert_reply, GINT_TO_POINTER(1), &error);
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionFlush(servertracker->session, TRUE, &error), NULL);
	
	smlDsSessionGetAlert(clienttracker->dssessions[0], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[1], _recv_alert, GINT_TO_POINTER(1));
	smlDsSessionGetAlert(clienttracker->dssessions[2], _recv_alert, GINT_TO_POINTER(1));
	
	while (alerts_received < 6) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	const char *content_types[] = {SML_ELEMENT_TEXT_VCARD, SML_ELEMENT_TEXT_VCAL, SML_ELEMENT_TEXT_PLAIN};
	int k = 0;
	for (k = 0; k < 3; k++)
	{
		smlDsSessionSendSync(clienttracker->dssessions[k], num_changes, _sync_reply, GINT_TO_POINTER(1), &error);
	
		unsigned int i = 0;
		for (i = 0; i < num_items; i++) {
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_ADD, "uid", "data", 4, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _add_reply, GINT_TO_POINTER(2), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_REPLACE, "uid", "newdata", 7, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _modify_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_NEW(SML_CHANGE_DELETE, "uid", NULL, 0, content_types[k]);
			sml_fail_unless(smlDsSessionQueueChange(clienttracker->dssessions[k], TEST_DATA_SYNC_CHANGE_ITEM, _delete_reply, GINT_TO_POINTER(1), &error), NULL);
			TEST_DATA_SYNC_CHANGE_ITEM_FREE();
			sml_fail_unless(error == NULL, NULL);
		}

		smlDsSessionCloseSync(clienttracker->dssessions[k], &error);
	}
	
	sml_fail_unless(smlSessionFlush(clienttracker->session, TRUE, &error), "%s", GET_ERROR_MESSAGE(error));
	
	smlDsSessionGetSync(servertracker->dssessions[0], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[1], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetSync(servertracker->dssessions[2], _recv_sync, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[0], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[1], _recv_changes, GINT_TO_POINTER(1));
	smlDsSessionGetChanges(servertracker->dssessions[2], _recv_changes, GINT_TO_POINTER(1));
	
	while (syncs_received < 3 || adds_received < num_items * 3 || deletes_received < num_items * 3 || modifies_received < num_items * 3) {
		smlDsSessionDispatch(servertracker->dssessions[0]);
		smlDsSessionDispatch(servertracker->dssessions[1]);
		smlDsSessionDispatch(servertracker->dssessions[2]);
		
		smlDsSessionDispatch(clienttracker->dssessions[0]);
		smlDsSessionDispatch(clienttracker->dssessions[1]);
		smlDsSessionDispatch(clienttracker->dssessions[2]);
		
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(servertracker->session != NULL, NULL);
	sml_fail_unless(smlSessionEnd(servertracker->session, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(error == NULL, NULL);
	smlSessionUnref(servertracker->session);
	smlSessionUnref(clienttracker->session);
	
	while (num_end < 2 || replies_received < 9 || num_finals < 5) {
		smlManagerDispatch(servermanager);
		smlManagerDispatch(clientmanager);
		usleep(100);
		sml_fail_unless(eventError == NULL, "%s",  GET_ERROR_MESSAGE(eventError));
	}
	
	sml_fail_unless(init_alerts_received == 3, NULL);
	sml_fail_unless(alerts_received == 6, NULL);
	sml_fail_unless(syncs_received == 3, NULL);
	sml_fail_unless(sync_ends_received == 0, NULL);
	sml_fail_unless(changes_received == 0, NULL);
	sml_fail_unless(replies_received == 9, NULL);
	sml_fail_unless(adds_received == num_items * 3, NULL);
	sml_fail_unless(add_replies_received == num_items * 3, NULL);
	sml_fail_unless(deletes_received == num_items * 3, NULL);
	sml_fail_unless(delete_replies_received == num_items * 3, NULL);
	sml_fail_unless(modifies_received == num_items * 3, NULL);
	sml_fail_unless(modify_replies_received == num_items * 3, NULL);
	sml_fail_unless(transport_errors == 0, NULL);
	sml_fail_unless(num_sessions == 2, NULL);
	sml_fail_unless(num_finals == 5, NULL);
	sml_fail_unless(num_end == 2, NULL);
	sml_fail_unless(session_errors == 0, NULL);

	smlDsSessionUnref(clienttracker->dssessions[0]);
	smlDsSessionUnref(clienttracker->dssessions[1]);
	smlDsSessionUnref(clienttracker->dssessions[2]);
	
	smlDsSessionUnref(servertracker->dssessions[0]);
	smlDsSessionUnref(servertracker->dssessions[1]);
	smlDsSessionUnref(servertracker->dssessions[2]);
	
	smlDsServerFree(clienttracker->ds[0]);
	smlDsServerFree(clienttracker->ds[1]);
	smlDsServerFree(clienttracker->ds[2]);
	
	smlDsServerFree(servertracker->ds[0]);
	smlDsServerFree(servertracker->ds[1]);
	smlDsServerFree(servertracker->ds[2]);
	
	smlAuthFree(auth);
	smlAuthFree(auth2);
	
	g_free(clienttracker);
	g_free(servertracker);
	
	/* first we have to stop the OBEX client or we get errors */

	smlManagerStop(servermanager);
	while(num_disconnects < 1) {
		smlManagerDispatch(servermanager);
	}
	smlManagerStop(clientmanager);
	while(num_disconnects < 2) {
		smlManagerDispatch(clientmanager);
	}
	
	
	smlManagerFree(clientmanager);
	smlManagerFree(servermanager);
	
	sml_fail_unless(smlTransportFinalize(server, &error), "%s", GET_ERROR_MESSAGE(error));
	sml_fail_unless(smlTransportFinalize(client, &error), "%s", GET_ERROR_MESSAGE(error));
	
	smlTransportFree(server);
	smlTransportFree(client);
}
END_TEST
#endif
#endif

@SML_TESTCASE_CODE@

