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

#include "syncml_internals.h"
#include "sml_devinf_internals.h"
#include "sml_command_internals.h"
#include "sml_elements_internals.h"
#include "sml_parse_internals.h"
#include "parser/sml_xml_assm.h"
#include "parser/sml_xml_parse.h"
#include "sml_error_internals.h"

SmlDevInfDevTyp smlDevInfDevTypeFromString(const char *name, SmlError **error)
{
	CHECK_ERROR_REF

	if (!strcmp(name, SML_ELEMENT_DEVTYP_PAGER)) {
		return SML_DEVINF_DEVTYPE_PAGER;
	} else if (!strcmp(name, SML_ELEMENT_DEVTYP_HANDHELD)) {
		return SML_DEVINF_DEVTYPE_HANDHELD;
	} else if (!strcmp(name, SML_ELEMENT_DEVTYP_PDA)) {
		return SML_DEVINF_DEVTYPE_PDA;
	} else if (!strcmp(name, SML_ELEMENT_DEVTYP_PHONE)) {
		return SML_DEVINF_DEVTYPE_PHONE;
	} else if (!strcmp(name, SML_ELEMENT_DEVTYP_SMARTPHONE)) {
		return SML_DEVINF_DEVTYPE_SMARTPHONE;
	} else if (!strcmp(name, SML_ELEMENT_DEVTYP_SERVER)) {
		return SML_DEVINF_DEVTYPE_SERVER;
	} else if (!strcmp(name, SML_ELEMENT_DEVTYP_WORKSTATION)) {
		return SML_DEVINF_DEVTYPE_WORKSTATION;
	}
	
	smlErrorSet(error, SML_ERROR_GENERIC, "Unknown devinf type name \"%s\"", name);
	return SML_DEVINF_DEVTYPE_UNKNOWN;
}

const char *smlDevInfDevTypeToString(SmlDevInfDevTyp type, SmlError **error)
{
	CHECK_ERROR_REF

	switch (type) {
		case SML_DEVINF_DEVTYPE_PAGER:
			return SML_ELEMENT_DEVTYP_PAGER;
		case SML_DEVINF_DEVTYPE_HANDHELD:
			return SML_ELEMENT_DEVTYP_HANDHELD;
		case SML_DEVINF_DEVTYPE_PDA:
			return SML_ELEMENT_DEVTYP_PDA;
		case SML_DEVINF_DEVTYPE_PHONE:
			return SML_ELEMENT_DEVTYP_PHONE;
		case SML_DEVINF_DEVTYPE_SMARTPHONE:
			return SML_ELEMENT_DEVTYP_SMARTPHONE;
		case SML_DEVINF_DEVTYPE_SERVER:
			return SML_ELEMENT_DEVTYP_SERVER;
		case SML_DEVINF_DEVTYPE_WORKSTATION:
			return SML_ELEMENT_DEVTYP_WORKSTATION;
		case SML_DEVINF_DEVTYPE_UNKNOWN:
			smlErrorSet(error, SML_ERROR_GENERIC, "Unknown devinf type \"%i\"", type);
			/* fall through! */
	}
		
	return NULL;
}

SmlDevInf *smlDevInfNew(const char *devid, SmlDevInfDevTyp devtyp, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%s, %i, %p)", __func__, VA_STRING(devid), devtyp, error);
	CHECK_ERROR_REF
	smlAssert(devid);
	
	SmlDevInf *devinf = smlTryMalloc0(sizeof(SmlDevInf), error);
	if (!devinf)
		goto error;
	
	devinf->devid = g_strdup(devid);
	devinf->devtyp = devtyp;
	devinf->refCount = 1;
	
	smlTrace(TRACE_EXIT, "%s: %p", __func__, devinf);
	return devinf;

error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;	
}

SmlDevInf *smlDevInfRef(SmlDevInf *devinf)
{
	smlTrace(TRACE_ENTRY, "%s(%p)", __func__, devinf);
	smlAssert(devinf);
	
	g_atomic_int_inc(&(devinf->refCount));
	
	smlTrace(TRACE_EXIT, "%s: New refcount: %i", __func__, devinf->refCount);
	return devinf;
}

void smlDevInfUnref(SmlDevInf *devinf)
{
	smlTrace(TRACE_ENTRY, "%s(%p)", __func__, devinf);
	smlAssert(devinf);
	
	if (g_atomic_int_dec_and_test(&(devinf->refCount))) {
		smlTrace(TRACE_INTERNAL, "%s: Refcount == 0!", __func__);
		
		if (devinf->manufacturer)
			smlSafeCFree(&(devinf->manufacturer));
		if (devinf->model)
			smlSafeCFree(&(devinf->model));
		if (devinf->oem)
			smlSafeCFree(&(devinf->oem));
		if (devinf->softwareVersion)
			smlSafeCFree(&(devinf->softwareVersion));
		if (devinf->hardwareVersion)
			smlSafeCFree(&(devinf->hardwareVersion));
		if (devinf->firmwareVersion)
			smlSafeCFree(&(devinf->firmwareVersion));
		if (devinf->devid)
			smlSafeCFree(&(devinf->devid));
		
		while (devinf->datastores) {
			SmlDevInfDataStore *store = devinf->datastores->data;
			devinf->datastores = g_list_remove(devinf->datastores, store);
			smlDevInfDataStoreUnref(store);
		}
		
		while (devinf->ctcaps) {
			SmlDevInfCTCap *ctcap = devinf->ctcaps->data;
			devinf->ctcaps = g_list_remove(devinf->ctcaps, ctcap);
			smlSafeCFree(&(ctcap->ct->cttype));
			if (ctcap->ct->verct)
				smlSafeCFree(&(ctcap->ct->verct));
			smlSafeFree((gpointer *)&(ctcap->ct));
			while (ctcap->properties) {
				SmlDevInfProperty *prop = ctcap->properties->data;
				ctcap->properties = g_list_remove(ctcap->properties, prop);
				smlSafeCFree(&(prop->propName));
				if (prop->dataType)
					smlSafeCFree(&(prop->dataType));
				if (prop->displayName)
					smlSafeCFree(&(prop->displayName));
				/* if lists are removed
				 * then the data must be removed separately
				 */
				while (prop->valEnums) {
					char *valEnum = prop->valEnums->data;
					prop->valEnums = g_list_remove(prop->valEnums, valEnum);
					smlSafeCFree(&valEnum);
				}
				while (prop->propParams) {
					SmlDevInfPropParam *param = prop->propParams->data;
					prop->propParams = g_list_remove(prop->propParams, param);
					smlSafeCFree(&(param->paramName));
					if (param->dataType)
						smlSafeCFree(&(param->dataType));
					if (param->displayName)
						smlSafeCFree(&(param->displayName));
					/* if lists are removed
					 * then the data must be removed separately
					 */
					while (param->valEnums) {
						char *valEnum = param->valEnums->data;
						param->valEnums = g_list_remove(param->valEnums, valEnum);
						smlSafeCFree(&valEnum);
					}
					/* free PropParam itself */
					smlSafeFree((gpointer *) &param);
				}
				/* free Property itself */
				smlSafeFree((gpointer *) &prop);
			}
			/* don't use ctcap here because the list must be cleaned up */
			smlSafeFree((gpointer *)&ctcap);
		}
		
		smlSafeFree((gpointer *)&devinf);
	}
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

const char *smlDevInfGetManufacturer(SmlDevInf *devinf)
{
	return devinf->manufacturer;
}

void smlDevInfSetManufacturer(SmlDevInf *devinf, const char *man)
{
	if (devinf->manufacturer)
		smlSafeCFree(&(devinf->manufacturer));
	devinf->manufacturer = g_strdup(man);
}

const char *smlDevInfGetModel(SmlDevInf *devinf)
{
	return devinf->model;
}

void smlDevInfSetModel(SmlDevInf *devinf, const char *model)
{
	if (devinf->model)
		smlSafeCFree(&(devinf->model));
	devinf->model = g_strdup(model);
}

const char *smlDevInfGetOEM(SmlDevInf *devinf)
{
	return devinf->oem;
}

void smlDevInfSetOEM(SmlDevInf *devinf, const char *oem)
{
	if (devinf->oem)
		smlSafeCFree(&(devinf->oem));
	devinf->oem = g_strdup(oem);
}

const char *smlDevInfGetFirmwareVersion(SmlDevInf *devinf)
{
	return devinf->firmwareVersion;
}

void smlDevInfSetFirmwareVersion(SmlDevInf *devinf, const char *firmwareVersion)
{
	if (devinf->firmwareVersion)
		smlSafeCFree(&(devinf->firmwareVersion));
	devinf->firmwareVersion = g_strdup(firmwareVersion);
}

const char *smlDevInfGetSoftwareVersion(SmlDevInf *devinf)
{
	return devinf->softwareVersion;
}

void smlDevInfSetSoftwareVersion(SmlDevInf *devinf, const char *softwareVersion)
{
	if (devinf->softwareVersion)
		smlSafeCFree(&(devinf->softwareVersion));
	devinf->softwareVersion = g_strdup(softwareVersion);
}

const char *smlDevInfGetHardwareVersion(SmlDevInf *devinf)
{
	return devinf->hardwareVersion;
}

void smlDevInfSetHardwareVersion(SmlDevInf *devinf, const char *hardwareVersion)
{
	if (devinf->hardwareVersion)
		smlSafeCFree(&(devinf->hardwareVersion));
	devinf->hardwareVersion = g_strdup(hardwareVersion);
}

const char *smlDevInfGetDeviceID(SmlDevInf *devinf)
{
	return devinf->devid;
}

void smlDevInfSetDeviceID(SmlDevInf *devinf, const char *devid)
{
	if (devinf->devid)
		smlSafeCFree(&(devinf->devid));
	devinf->devid = g_strdup(devid);
}

SmlDevInfDevTyp smlDevInfGetDeviceType(SmlDevInf *devinf)
{
	return devinf->devtyp;
}

void smlDevInfSetDeviceType(SmlDevInf *devinf, SmlDevInfDevTyp devtyp)
{
	devinf->devtyp = devtyp;
}

SmlBool smlDevInfSupportsUTC(SmlDevInf *devinf)
{
	return devinf->supportsUTC;
}

void smlDevInfSetSupportsUTC(SmlDevInf *devinf, SmlBool supports)
{
	devinf->supportsUTC = supports;
}

SmlBool smlDevInfSupportsLargeObjs(SmlDevInf *devinf)
{
	return devinf->supportsLargeObjs;
}

void smlDevInfSetSupportsLargeObjs(SmlDevInf *devinf, SmlBool supports)
{
	devinf->supportsLargeObjs = supports;
}

SmlBool smlDevInfSupportsNumberOfChanges(SmlDevInf *devinf)
{
	return devinf->supportsNumberOfChanges;
}

void smlDevInfSetSupportsNumberOfChanges(SmlDevInf *devinf, SmlBool supports)
{
	devinf->supportsNumberOfChanges = supports;
}

void smlDevInfAddDataStore(SmlDevInf *devinf, SmlDevInfDataStore *datastore)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, devinf, datastore);
	smlAssert(devinf);
	smlAssert(datastore);
	
	devinf->datastores = g_list_append(devinf->datastores, datastore);
	
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

unsigned int smlDevInfNumDataStores(SmlDevInf *devinf)
{
	smlAssert(devinf);
	
	return g_list_length(devinf->datastores);
}

const SmlDevInfDataStore *smlDevInfGetNthDataStore(const SmlDevInf *devinf, unsigned int nth)
{
	smlAssert(devinf);
	
	return g_list_nth_data(devinf->datastores, nth);
}

SmlDevInfDataStore *smlDevInfDataStoreNew(const char *sourceRef, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, sourceRef, error);
	CHECK_ERROR_REF
	
	SmlDevInfDataStore *datastore = smlTryMalloc0(sizeof(SmlDevInfDataStore), error);
	if (!datastore)
		goto error;

	datastore->sourceref = g_strdup(sourceRef);
	datastore->refCount = 1;
	
	smlTrace(TRACE_EXIT, "%s: %p", __func__, datastore);
	return datastore;

error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;	
}


SmlDevInfDataStore *smlDevInfDataStoreRef(SmlDevInfDataStore *datastore)
{
	smlTrace(TRACE_ENTRY, "%s(%p)", __func__, datastore);
	smlAssert(datastore);
	
	g_atomic_int_inc(&(datastore->refCount));
	
	smlTrace(TRACE_EXIT, "%s: New refcount: %i", __func__, datastore->refCount);
	return datastore;
}

void smlDevInfDataStoreUnref(SmlDevInfDataStore *datastore)
{
	smlTrace(TRACE_ENTRY, "%s(%p)", __func__, datastore);
	smlAssert(datastore);
	
	if (g_atomic_int_dec_and_test(&(datastore->refCount))) {
		smlTrace(TRACE_INTERNAL, "%s: Refcount == 0!", __func__);
		
		smlSafeCFree(&(datastore->sourceref));
		if (datastore->displayname)
			smlSafeCFree(&(datastore->displayname));

		smlSafeCFree(&(datastore->rxPrefContentType));
		smlSafeCFree(&(datastore->rxPrefVersion));
		GList *d = NULL;
		for (d = datastore->rx; d; d = d->next) {
			SmlDevInfContentType *ct = d->data;
			smlDevInfFreeContentType(ct);
		}
		g_list_free(datastore->rx);

		smlSafeCFree(&(datastore->txPrefContentType));
		smlSafeCFree(&(datastore->txPrefVersion));
		for (d = datastore->tx; d; d = d->next) {
			SmlDevInfContentType *ct = d->data;
			smlDevInfFreeContentType(ct);
		}
		g_list_free(datastore->tx);

		smlSafeFree((gpointer *)&datastore);
	}
	
	smlTrace(TRACE_EXIT, "%s", __func__);
}

const char *smlDevInfDataStoreGetSourceRef(const SmlDevInfDataStore *datastore)
{
	return datastore->sourceref;
}

void smlDevInfDataStoreSetSourceRef(SmlDevInfDataStore *datastore, const char *sourceref)
{
	if (datastore->sourceref)
		smlSafeCFree(&(datastore->sourceref));
	datastore->sourceref = g_strdup(sourceref);
}

const char *smlDevInfDataStoreGetDisplayName(const SmlDevInfDataStore *datastore)
{
	return datastore->displayname;
}

void smlDevInfDataStoreSetDisplayName(SmlDevInfDataStore *datastore, const char *displayName)
{
	if (datastore->displayname)
		smlSafeCFree(&(datastore->displayname));
	datastore->displayname = g_strdup(displayName);
}

unsigned int smlDevInfGetMaxGUIDSize(const SmlDevInfDataStore *datastore)
{
	return datastore->maxGUIDSize;
}

void smlDevInfSetMaxGUIDSize(SmlDevInfDataStore *datastore, unsigned int max)
{
	datastore->maxGUIDSize = max;
}

void smlDevInfDataStoreSetRxPref(SmlDevInfDataStore *datastore, const char *contenttype, const char *version)
{
	if (datastore->rxPrefContentType)
		smlSafeCFree(&(datastore->rxPrefContentType));
	datastore->rxPrefContentType = g_strdup(contenttype);
	
	if (datastore->rxPrefVersion)
		smlSafeCFree(&(datastore->rxPrefVersion));
	datastore->rxPrefVersion = g_strdup(version);
}

SmlBool smlDevInfDataStoreGetRxPref(const SmlDevInfDataStore *datastore, char **contenttype, char **version)
{
	if (!datastore->rxPrefContentType)
		return FALSE;
	
	*contenttype = datastore->rxPrefContentType;
	*version = datastore->rxPrefVersion;
	
	return TRUE;
}

/* FIXME: DEPRECATED*/
void smlDevInfDataStoreSetRx(SmlDevInfDataStore *datastore, const char *contenttype, const char *version)
{
	SmlError *error = NULL;
	SmlDevInfContentType *ct = smlDevInfNewContentType(contenttype, version, &error);
	if (!ct)
	{
		smlTrace(TRACE_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
		smlErrorDeref(&error);
		return;
	}
	smlDevInfDataStoreAddRx(datastore, ct);
}

/* FIXME: DEPRECATED*/
SmlBool smlDevInfDataStoreGetRx(const SmlDevInfDataStore *datastore, char **contenttype, char **version)
{
	const SmlDevInfContentType *ct = smlDevInfDataStoreGetNthRx(datastore, 0);
	if (!ct)
		return FALSE;

	*contenttype = smlDevInfContentTypeGetCTType(ct);
	*version = smlDevInfContentTypeGetVerCT(ct);
	return TRUE;
}

void smlDevInfDataStoreAddRx(SmlDevInfDataStore *datastore, SmlDevInfContentType *ct)
{
	smlAssert(datastore);
	datastore->rx = g_list_append(datastore->rx, ct);
}

unsigned int smlDevInfDataStoreNumRx(const SmlDevInfDataStore *datastore)
{
	return g_list_length(datastore->rx);
}

const SmlDevInfContentType *smlDevInfDataStoreGetNthRx(
	const SmlDevInfDataStore *datastore,
	unsigned int n)
{
	return g_list_nth_data(datastore->rx, n);
}

void smlDevInfDataStoreSetTxPref(SmlDevInfDataStore *datastore, const char *contenttype, const char *version)
{
	if (datastore->txPrefContentType)
		smlSafeCFree(&(datastore->txPrefContentType));
	datastore->txPrefContentType = g_strdup(contenttype);
	
	if (datastore->txPrefVersion)
		smlSafeCFree(&(datastore->txPrefVersion));
	datastore->txPrefVersion = g_strdup(version);
}

SmlBool smlDevInfDataStoreGetTxPref(const SmlDevInfDataStore *datastore, char **contenttype, char **version)
{
	if (!datastore->txPrefContentType)
		return FALSE;
	
	*contenttype = datastore->txPrefContentType;
	*version = datastore->txPrefVersion;
	
	return TRUE;
}

/* FIXME: DEPRECATED*/
void smlDevInfDataStoreSetTx(SmlDevInfDataStore *datastore, const char *contenttype, const char *version)
{
	SmlError *error = NULL;
	SmlDevInfContentType *ct = smlDevInfNewContentType(contenttype, version, &error);
	if (!ct)
	{
		smlTrace(TRACE_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
		smlErrorDeref(&error);
		return;
	}
	smlDevInfDataStoreAddTx(datastore, ct);
}

/* FIXME: DEPRECATED*/
SmlBool smlDevInfDataStoreGetTx(const SmlDevInfDataStore *datastore, char **contenttype, char **version)
{
	const SmlDevInfContentType *ct = smlDevInfDataStoreGetNthRx(datastore, 0);
	if (!ct)
		return FALSE;

	*contenttype = smlDevInfContentTypeGetCTType(ct);
	*version = smlDevInfContentTypeGetVerCT(ct);
	return TRUE;
}

void smlDevInfDataStoreAddTx(SmlDevInfDataStore *datastore, SmlDevInfContentType *ct)
{
	smlAssert(datastore);
	datastore->tx = g_list_append(datastore->tx, ct);
}

unsigned int smlDevInfDataStoreNumTx(const SmlDevInfDataStore *datastore)
{
	return g_list_length(datastore->tx);
}

const SmlDevInfContentType *smlDevInfDataStoreGetNthTx(
	const SmlDevInfDataStore *datastore,
	unsigned int n)
{
	return g_list_nth_data(datastore->tx, n);
}

void smlDevInfDataStoreSetMemory(SmlDevInfDataStore *datastore, SmlBool shared, unsigned int maxid, unsigned int maxmem)
{
	datastore->sharedMem = shared;
	datastore->maxid = maxid;
	datastore->maxmem = maxmem;
}

void smlDevInfDataStoreGetMemory(const SmlDevInfDataStore *datastore, SmlBool *shared, unsigned int *maxid, unsigned int *maxmem)
{
	if (shared)
		*shared = datastore->sharedMem;
		
	if (maxid)
		*maxid = datastore->maxid;
		
	if (maxmem)
		*maxmem = datastore->maxmem;
}

void smlDevInfDataStoreSetSyncCap(SmlDevInfDataStore *datastore, SmlDevInfSyncCap cap, SmlBool supported)
{
	if (supported)
		datastore->synccap = datastore->synccap | cap;
	else
		datastore->synccap = datastore->synccap & ~cap;
}

SmlBool smlDevInfDataStoreGetSyncCap(const SmlDevInfDataStore *datastore, SmlDevInfSyncCap cap)
{
	return datastore->synccap & cap ? TRUE : FALSE;
}

void smlDevInfConfigureSession(SmlDevInf *devinf, SmlSession *session)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, devinf, session);
	smlAssert(devinf);
	smlAssert(session);
	
	if (!devinf->supportsNumberOfChanges)
		smlSessionUseNumberOfChanges(session, FALSE);
		
	if (!devinf->supportsLargeObjs)
		smlSessionUseLargeObjects(session, FALSE);
		
	smlTrace(TRACE_EXIT, "%s", __func__);
}

SmlBool smlDevInfAssemble(SmlDevInf *devinf, char **data, unsigned int *size, SmlError **error)
{
	CHECK_ERROR_REF
	return smlXmlDevInfAssemble(devinf, devinf->version, data, size, error);
}

SmlCommand *smlDevInfNewResult(SmlCommand *cmd, SmlDevInf *devinf, SmlDevInfVersion version, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p)", __func__, cmd, devinf, version, error);
	CHECK_ERROR_REF
	smlAssert(cmd);
	SmlLocation *source = NULL;

	char *data = NULL;
	unsigned int size = 0;
	if (!smlXmlDevInfAssemble(devinf, version, &data, &size, error))
		goto error;
	
	if (version == SML_DEVINF_VERSION_10)
		source = smlLocationNew("./devinf10", NULL, error);
	else if (version == SML_DEVINF_VERSION_12)
		source = smlLocationNew("./devinf12", NULL, error);
	else
		source = smlLocationNew("./devinf11", NULL, error);
		
	if (!source)
		goto error_free_data;
	
	SmlCommand *result = smlCommandNewResult(cmd, source, data, size, SML_ELEMENT_DEVINF_XML, error);
	if (!result) {
		smlLocationUnref(source);
		goto error_free_data;
	}
	/* Since the devinf is xml, we want to send it "raw" (without cdata) */
	result->private.results.status->item->raw = TRUE;
	
	smlLocationUnref(source);
	
	smlTrace(TRACE_EXIT, "%s: %p", __func__, result);
	return result;
	
error_free_data:
	smlSafeCFree(&data);
error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;
}

SmlCommand *smlDevInfNewPut(SmlDevInf *devinf, SmlDevInfVersion version, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, devinf, version, error);
	CHECK_ERROR_REF
	smlAssert(devinf);
	SmlLocation *source = NULL;

	// update version
	if (devinf->version == SML_DEVINF_VERSION_UNKNOWN)
		devinf->version = version;
	
	if (version == SML_DEVINF_VERSION_10)
		source = smlLocationNew("./devinf10", NULL, error);
	else if (version == SML_DEVINF_VERSION_12)
		source = smlLocationNew("./devinf12", NULL, error);
	else
		source = smlLocationNew("./devinf11", NULL, error);
		
	if (!source)
		goto error;
		
	SmlCommand *cmd = smlCommandNewPut(NULL, source, NULL, 0, SML_ELEMENT_DEVINF_XML, error);
	if (!cmd)
		goto error_free_source;
	
	smlLocationUnref(source);
	
	char *data = NULL;
	unsigned int size = 0;
	if (!smlXmlDevInfAssemble(devinf, version, &data, &size, error))
		goto error_free_cmd;
	
	if (!smlItemAddData(cmd->private.access.item, data, size, error)) {
		smlSafeCFree(&data);
		goto error_free_cmd;
	}
	smlSafeCFree(&data);
	smlItemSetRaw(cmd->private.access.item, TRUE);
	
	smlTrace(TRACE_EXIT, "%s: %p", __func__, cmd);
	return cmd;
	
error_free_cmd:
	smlCommandUnref(cmd);
error_free_source:
	smlLocationUnref(source);
error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;
}

SmlCommand *smlDevInfNewGet(SmlDevInfVersion version, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%i, %p)", __func__, version, error);
	CHECK_ERROR_REF
	SmlLocation *target = NULL;
	
	if (version == SML_DEVINF_VERSION_10)
		target = smlLocationNew("./devinf10", NULL, error);
	else if (version == SML_DEVINF_VERSION_12)
		target = smlLocationNew("./devinf12", NULL, error);
	else
		target = smlLocationNew("./devinf11", NULL, error);
		
	if (!target)
		goto error;
		
	SmlCommand *cmd = smlCommandNewGet(target, SML_ELEMENT_DEVINF_XML, error);
	if (!cmd)
		goto error_free_target;
	
	smlLocationUnref(target);
	
	smlTrace(TRACE_EXIT, "%s: %p", __func__, cmd);
	return cmd;
	
error_free_target:
	smlLocationUnref(target);
error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;
}

SmlDevInf *smlDevInfParse(const char *data, unsigned int length, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, data, length, error);
	CHECK_ERROR_REF
	smlAssert(data);
	smlAssert(length);
	
	SmlDevInf *devinf = smlXmlDevInfParse(data, length, error);
	if (!devinf)
		goto error;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
	return devinf;
	
error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;
}

SmlDevInf *smlDevInfFromResult(SmlCommand *result, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, result, error);
	CHECK_ERROR_REF
	smlAssert(result);
	
	if (result->type != SML_COMMAND_TYPE_RESULTS) {
		smlErrorSet(error, SML_ERROR_GENERIC, "devinf command was not a result");
		goto error;
	}
	
	SmlItem *item = result->private.results.status->item;
	if (!item) {
		smlErrorSet(error, SML_ERROR_GENERIC, "devinf result did not have a item");
		goto error;
	}
	
	char *data = NULL;
	unsigned int size = 0;
	if (!smlItemGetData(item, &data, &size, error))
		goto error;
	
	SmlDevInf *devinf = smlDevInfParse(data, size, error);
	if (!devinf)
		goto error;
	
	smlTrace(TRACE_EXIT, "%s", __func__);
	return devinf;
	
error:
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	return NULL;
}

SmlDevInfCTCapType smlDevInfCTCapTypeFromString(const char *name, SmlError **error)
{
	CHECK_ERROR_REF

	if (!strcmp(name, SML_ELEMENT_CTTYPE)) {
		return SML_DEVINF_CTCAP_CTTYPE;
	} else if (!strcmp(name, SML_ELEMENT_PROPNAME)) {
		return SML_DEVINF_CTCAP_PROPNAME;
	} else if (!strcmp(name, SML_ELEMENT_VALENUM)) {
		return SML_DEVINF_CTCAP_VALENUM;
	} else if (!strcmp(name, SML_ELEMENT_DATATYPE)) {
		return SML_DEVINF_CTCAP_DATATYPE;
	} else if (!strcmp(name, SML_ELEMENT_SIZE)) {
		return SML_DEVINF_CTCAP_SIZE;
	} else if (!strcmp(name, SML_ELEMENT_DISPLAYNAME)) {
		return SML_DEVINF_CTCAP_DISPLAYNAME;
	} else if (!strcmp(name, SML_ELEMENT_PARAMNAME)) {
		return SML_DEVINF_CTCAP_PARAMNAME;
	} else if (!strcmp(name, SML_ELEMENT_VERCT)) {
		return SML_DEVINF_CTCAP_VERCT;
	} else if (!strcmp(name, SML_ELEMENT_PROPERTY)) {
		return SML_DEVINF_CTCAP_PROPERTY;
	} else if (!strcmp(name, SML_ELEMENT_PROPPARAM)) {
		return SML_DEVINF_CTCAP_PROPPARAM;
	} else if (!strcmp(name, SML_ELEMENT_NOTRUNCATE)) {
		return SML_DEVINF_CTCAP_NOTRUNCATE;
	} else if (!strcmp(name, SML_ELEMENT_MAXOCCUR)) {
		return SML_DEVINF_CTCAP_MAXOCCUR;
	} else if (!strcmp(name, SML_ELEMENT_MAXSIZE)) {
		return SML_DEVINF_CTCAP_MAXSIZE;
	}
	
	smlErrorSet(error, SML_ERROR_GENERIC, "Unknown ctcap type name \"%s\"", name);
	smlTrace(TRACE_ERROR, "%s - %s", __func__, smlErrorPrint(error));
	return SML_DEVINF_CTCAP_UNKNOWN;
}


const char *smlDevInfCTCapTypeToString(SmlDevInfCTCapType type, SmlError **error)
{
	CHECK_ERROR_REF

	switch (type) {
		case SML_DEVINF_CTCAP_CTTYPE:
			return SML_ELEMENT_CTTYPE;
		case SML_DEVINF_CTCAP_PROPNAME:
			return SML_ELEMENT_PROPNAME;
		case SML_DEVINF_CTCAP_VALENUM:
			return SML_ELEMENT_VALENUM;
		case SML_DEVINF_CTCAP_DATATYPE:
			return SML_ELEMENT_DATATYPE;
		case SML_DEVINF_CTCAP_SIZE:
			return SML_ELEMENT_SIZE;
		case SML_DEVINF_CTCAP_DISPLAYNAME:
			return SML_ELEMENT_DISPLAYNAME;
		case SML_DEVINF_CTCAP_PARAMNAME:
			return SML_ELEMENT_PARAMNAME;
		case SML_DEVINF_CTCAP_NOTRUNCATE:
			return SML_ELEMENT_NOTRUNCATE;
		case SML_DEVINF_CTCAP_MAXOCCUR:
			return SML_ELEMENT_MAXOCCUR;
		case SML_DEVINF_CTCAP_VERCT:
			return SML_ELEMENT_VERCT;
		case SML_DEVINF_CTCAP_PROPERTY:
			return SML_ELEMENT_PROPERTY;
		case SML_DEVINF_CTCAP_PROPPARAM:
			return SML_ELEMENT_PROPPARAM;
		case SML_DEVINF_CTCAP_MAXSIZE:
			return SML_ELEMENT_MAXSIZE;
		case SML_DEVINF_CTCAP_UNKNOWN:
			smlErrorSet(error, SML_ERROR_GENERIC, "Unknown ctcap type \"%i\"", type);
			/* fall through! */
	}
	
	return NULL;
}

/* PropParam stuff */

SmlDevInfPropParam *smlDevInfNewPropParam(SmlError **error)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, error);
    CHECK_ERROR_REF

    SmlDevInfPropParam *param = smlTryMalloc0(sizeof(SmlDevInfPropParam), error);
    if (!param) {
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
        return NULL;
    }

    param->paramName = NULL;
    param->dataType = NULL;
    param->displayName = NULL;
    param->valEnums = NULL;

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

void smlDevInfPropParamSetParamName(
			SmlDevInfPropParam *propParam,
			const char *paramName)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, propParam, VA_STRING(paramName));
    smlAssert(propParam);
    smlAssert(paramName);

    if (propParam->paramName != NULL)
        smlSafeCFree(&(propParam->paramName));
    propParam->paramName = g_strdup(paramName);

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

void smlDevInfPropParamSetDataType(
			SmlDevInfPropParam *propParam,
			const char *dataType)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, propParam, VA_STRING(dataType));
    smlAssert(propParam);
    smlAssert(dataType);

    if (propParam->dataType != NULL)
        smlSafeCFree(&(propParam->dataType));
    propParam->dataType = g_strdup(dataType);

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

void smlDevInfPropParamSetDisplayName(
			SmlDevInfPropParam *propParam,
			const char *displayName)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, propParam, VA_STRING(displayName));
    smlAssert(propParam);
    smlAssert(displayName);

    if (propParam->displayName != NULL)
        smlSafeCFree(&(propParam->displayName));
    propParam->displayName = g_strdup(displayName);

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

void smlDevInfPropParamAddValEnum(
			SmlDevInfPropParam *propParam,
			const char *valEnum)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, propParam, VA_STRING(valEnum));
    smlAssert(propParam);
    smlAssert(valEnum);
    propParam->valEnums = g_list_append(propParam->valEnums, g_strdup(valEnum));
    smlTrace(TRACE_EXIT, "%s", __func__);
}

char *smlDevInfPropParamGetParamName(const SmlDevInfPropParam *propParam)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, propParam);
    smlAssert(propParam);
    char *result = g_strdup(propParam->paramName);
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

char *smlDevInfPropParamGetDataType(const SmlDevInfPropParam *propParam)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, propParam);
    smlAssert(propParam);
    char *result = g_strdup(propParam->dataType);
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

char *smlDevInfPropParamGetDisplayName(const SmlDevInfPropParam *propParam)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, propParam);
    smlAssert(propParam);
    char *result = g_strdup(propParam->displayName);
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

unsigned int smlDevInfPropParamNumValEnums(const SmlDevInfPropParam *propParam)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, propParam);
    smlAssert(propParam);
    unsigned int num = g_list_length(propParam->valEnums);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, num);
    return num;
}

char *smlDevInfPropParamGetNthValEnum(
			const SmlDevInfPropParam *propParam,
			unsigned int n)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, propParam, n);
    smlAssert(propParam);
    char *result = g_strdup(g_list_nth_data(propParam->valEnums, n));
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

/* Property stuff */

SmlDevInfProperty *smlDevInfNewProperty(SmlError **error)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, error);
    CHECK_ERROR_REF

    SmlDevInfProperty *property = smlTryMalloc0(sizeof(SmlDevInfProperty), error);
    if (!property) {
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
        return NULL;
    }

    property->propName = NULL;
    property->dataType = NULL;
    property->maxOccur = 0;
    property->maxSize = 0;
    property->noTruncate = FALSE;
    property->displayName = NULL;
    property->valEnums = NULL;
    property->propParams = NULL;

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

void smlDevInfPropertySetPropName(
			SmlDevInfProperty *property,
			const char *propName)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, property, VA_STRING(propName));
    smlAssert(property);
    smlAssert(propName);

    if (property->propName != NULL)
        smlSafeCFree(&(property->propName));
    property->propName = g_strdup(propName);

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

void smlDevInfPropertySetDataType(
			SmlDevInfProperty *property,
			const char *dataType)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, property, VA_STRING(dataType));
    smlAssert(property);
    smlAssert(dataType);

    if (property->dataType != NULL)
        smlSafeCFree(&(property->dataType));
    property->dataType = g_strdup(dataType);

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

void smlDevInfPropertySetMaxOccur(
			SmlDevInfProperty *property,
			unsigned int maxOccur)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, property, maxOccur);
    smlAssert(property);

    property->maxOccur = maxOccur;

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

void smlDevInfPropertySetMaxSize(
			SmlDevInfProperty *property,
			unsigned int maxSize)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, property, maxSize);
    smlAssert(property);

    property->maxSize = maxSize;

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

void smlDevInfPropertySetPropSize(
			SmlDevInfProperty *property,
			unsigned int propSize)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, property, propSize);
    smlAssert(property);

    property->propSize = propSize;

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

void smlDevInfPropertySetNoTruncate(
			SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);

    property->noTruncate = TRUE;

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

void smlDevInfPropertySetDisplayName(
			SmlDevInfProperty *property,
			const char *displayName)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, property, VA_STRING(displayName));
    smlAssert(property);
    smlAssert(displayName);

    if (property->displayName != NULL)
        smlSafeCFree(&(property->displayName));
    property->displayName = g_strdup(displayName);

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

void smlDevInfPropertyAddValEnum(
			SmlDevInfProperty *property,
			const char *valEnum)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, property, VA_STRING(valEnum));
    smlAssert(property);
    smlAssert(valEnum);
    property->valEnums = g_list_append(property->valEnums, g_strdup(valEnum));
    smlTrace(TRACE_EXIT, "%s", __func__);
}

void smlDevInfPropertyAddPropParam(
			SmlDevInfProperty *property,
			SmlDevInfPropParam *propParam)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, property, propParam);
    smlAssert(property);
    smlAssert(propParam);
    property->propParams = g_list_append(property->propParams, propParam);
    smlTrace(TRACE_EXIT, "%s", __func__);
}

char *smlDevInfPropertyGetPropName(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    char *result = g_strdup(property->propName);
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

char *smlDevInfPropertyGetDataType(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    char *result = g_strdup(property->dataType);
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

unsigned int smlDevInfPropertyGetMaxOccur(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, property->maxOccur);
    return property->maxOccur;
}

unsigned int smlDevInfPropertyGetMaxSize(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, property->maxSize);
    return property->maxSize;
}

SmlBool smlDevInfPropertyGetNoTruncate(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, property->noTruncate);
    return property->noTruncate;
}

char *smlDevInfPropertyGetDisplayName(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    char *result = g_strdup(property->displayName);
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

unsigned int smlDevInfPropertyNumValEnums(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    unsigned int num = g_list_length(property->valEnums);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, num);
    return num;
}

char *smlDevInfPropertyGetNthValEnum(
			const SmlDevInfProperty *property,
			unsigned int n)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, property, n);
    smlAssert(property);
    char *result = g_strdup(g_list_nth_data(property->valEnums, n));
    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
    return result;
}

unsigned int smlDevInfPropertyNumPropParams(const SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, property);
    smlAssert(property);
    unsigned int num = g_list_length(property->propParams);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, num);
    return num;
}

const SmlDevInfPropParam *smlDevInfPropertyGetNthPropParam(
			const SmlDevInfProperty *property,
			unsigned int n)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, property, n);
    smlAssert(property);
    SmlDevInfPropParam *param = g_list_nth_data(property->propParams, n);
    smlTrace(TRACE_EXIT, "%s - %p", __func__, param);
    return param;
}

/* CTCap stuff */

SmlDevInfContentType *smlDevInfNewContentType(
			const char *cttype,
			const char *verct,
			SmlError **error)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, error);
    CHECK_ERROR_REF

    SmlDevInfContentType *ct = smlTryMalloc0(sizeof(SmlDevInfContentType), error);
    if (!ct) {
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
        return NULL;
    }

    if (cttype != NULL)
    	ct->cttype = g_strdup(cttype);
    else
        ct->cttype = NULL;
    if (verct != NULL)
        ct->verct = g_strdup(verct);
    else
        ct->verct = NULL;

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

char *smlDevInfContentTypeGetCTType(const SmlDevInfContentType *ct)
{
	return g_strdup(ct->cttype);
}

char *smlDevInfContentTypeGetVerCT(const SmlDevInfContentType *ct)
{
	return g_strdup(ct->verct);
}

void smlDevInfFreeContentType(SmlDevInfContentType *ct)
{
    smlTrace(TRACE_ENTRY, "%s", __func__);
    smlAssert(ct);

    if (ct->cttype != NULL)
        smlSafeCFree(&(ct->cttype));
    if (ct->verct != NULL)
        smlSafeCFree(&(ct->verct));
    smlSafeFree((gpointer *)&ct);

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

SmlDevInfCTCap *smlDevInfNewCTCap(SmlError **error)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, error);
    CHECK_ERROR_REF

    SmlDevInfCTCap *ctcap = smlTryMalloc0(sizeof(SmlDevInfCTCap), error);
    if (!ctcap) {
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
        return NULL;
    }

    ctcap->ct = smlDevInfNewContentType(NULL, NULL, error);
    if (!ctcap->ct) {
	smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
	smlSafeFree((gpointer *)&ctcap);
        return NULL;
    }
    ctcap->properties = NULL;

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

void smlDevInfCTCapSetCTType(
			SmlDevInfCTCap *ctcap,
			const char *cttype)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, ctcap, VA_STRING(cttype));
    smlAssert(ctcap);
    smlAssert(cttype);

    ctcap->ct->cttype = g_strdup(cttype);

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

void smlDevInfCTCapSetVerCT(
			SmlDevInfCTCap *ctcap,
			const char *verct)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, ctcap, VA_STRING(verct));
    smlAssert(ctcap);
    smlAssert(verct);

    ctcap->ct->verct = g_strdup(verct);

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

char *smlDevInfCTCapGetCTType(const SmlDevInfCTCap *ctcap)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, ctcap);
    smlAssert(ctcap);
    char *cttype;

    cttype = g_strdup(ctcap->ct->cttype);

    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(cttype));
    return cttype;
}

char *smlDevInfCTCapGetVerCT(const SmlDevInfCTCap *ctcap)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, ctcap);
    smlAssert(ctcap);
    char *verct;

    verct = g_strdup(ctcap->ct->verct);

    smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(verct));
    return verct;
}

void smlDevInfCTCapAddProperty(
			SmlDevInfCTCap *ctcap,
			SmlDevInfProperty *property)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, ctcap, property);
    smlAssert(ctcap);
    smlAssert(property);
    ctcap->properties = g_list_append(ctcap->properties, property);
    smlTrace(TRACE_EXIT, "%s", __func__);
}

void smlDevInfAppendCTCap(SmlDevInf *devinf, SmlDevInfCTCap *ctcap)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, devinf, ctcap);
    smlAssert(devinf);
    smlAssert(ctcap);
    devinf->ctcaps = g_list_append(devinf->ctcaps, ctcap);
    smlTrace(TRACE_EXIT, "%s", __func__);
}

/* FIXME: DEPRECATED*/
void smlDevInfAddCTCap(SmlDevInf *devinf, SmlDevInfCTCapType type, const char *value)
{
	SmlDevInfCTCap *ctcap = smlDevInfNewCTCap(NULL);
	smlDevInfCTCapSetCTType(ctcap, smlDevInfCTCapTypeToString(type, NULL));
	smlDevInfCTCapSetVerCT(ctcap, value);
	smlDevInfAppendCTCap(devinf, ctcap);
}

/* FIXME: DEPRECATED*/
SmlDevInfCTCapType smlDevInfGetNthCTCapType(SmlDevInf *devinf, unsigned int nth)
{
	const SmlDevInfCTCap *ctcap = smlDevInfGetNthCTCap(devinf, nth);
	char *type = smlDevInfCTCapGetCTType(ctcap);
	SmlError *error = NULL;
	SmlDevInfCTCapType cttype = smlDevInfCTCapTypeFromString(type, &error);
	smlSafeCFree(&type);
	return cttype;
}

/* FIXME: DEPRECATED*/
const char *smlDevInfGetNthCTCapValue(SmlDevInf *devinf, unsigned int nth)
{
	const SmlDevInfCTCap *ctcap = smlDevInfGetNthCTCap(devinf, nth);
	return smlDevInfCTCapGetVerCT(ctcap);
}

const SmlDevInfCTCap *smlDevInfGetCTCap(
                        const SmlDevInf *devinf,
                        SmlDevInfContentType *ct)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, devinf, ct);
    smlAssert(devinf);
    smlAssert(ct);
    smlAssert(ct->cttype);
    smlAssert(ct->verct);

    GList *h;
    for (h = devinf->ctcaps; h; h = h->next)
    {
        SmlDevInfCTCap *ctcap = h->data;
        // check that CTType matches
        if (!strcmp(ct->cttype, ctcap->ct->cttype) &&
            !strcmp(ct->verct, ctcap->ct->verct))
        {
            smlTrace(TRACE_EXIT, "%s - succeeded", __func__);
            return ctcap;
        }
    }
    smlTrace(TRACE_EXIT, "%s - nothing found", __func__);
    return NULL;
}

unsigned int smlDevInfNumCTCaps(const SmlDevInf *devinf)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, devinf);
    smlAssert(devinf);
    unsigned int num = g_list_length(devinf->ctcaps);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, num);
    return num;
}

const SmlDevInfCTCap *smlDevInfGetNthCTCap(
			const SmlDevInf *devinf,
			unsigned int n)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, devinf, n);
    smlAssert(devinf);
    SmlDevInfCTCap *ctcap = g_list_nth_data(devinf->ctcaps, n);
    smlTrace(TRACE_EXIT, "%s - %p", __func__, ctcap);
    return ctcap;
}

unsigned int smlDevInfCTCapNumProperties(const SmlDevInfCTCap *ctcap)
{
    smlTrace(TRACE_ENTRY, "%s(%p)", __func__, ctcap);
    smlAssert(ctcap);
    unsigned int num = g_list_length(ctcap->properties);
    smlTrace(TRACE_EXIT, "%s - %d", __func__, num);
    return num;
}

const SmlDevInfProperty *smlDevInfCTCapGetNthProperty(
			const SmlDevInfCTCap *ctcap,
			unsigned int n)
{
    smlTrace(TRACE_ENTRY, "%s(%p, %d)", __func__, ctcap, n);
    smlAssert(ctcap);
    SmlDevInfProperty *property = g_list_nth_data(ctcap->properties, n);
    smlTrace(TRACE_EXIT, "%s - %p", __func__, property);
    return property;
}

SmlDevInfSyncCap smlDevInfSyncCapConvert(unsigned int id, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%u, %p)", __func__, id, error);
	CHECK_ERROR_REF
	SmlDevInfSyncCap result = SML_DEVINF_SYNCTYPE_UNKNOWN;

	switch (id)
	{
		case SML_DEVINF_SYNCTYPE_TWO_WAY:
			result = SML_DEVINF_SYNCTYPE_TWO_WAY;
			break;
		case SML_DEVINF_SYNCTYPE_SLOW_SYNC:
			result = SML_DEVINF_SYNCTYPE_SLOW_SYNC;
			break;
		case SML_DEVINF_SYNCTYPE_ONE_WAY_FROM_CLIENT:
			result = SML_DEVINF_SYNCTYPE_ONE_WAY_FROM_CLIENT;
			break;
		case SML_DEVINF_SYNCTYPE_REFRESH_FROM_CLIENT:
			result = SML_DEVINF_SYNCTYPE_REFRESH_FROM_CLIENT;
			break;
		case SML_DEVINF_SYNCTYPE_ONE_WAY_FROM_SERVER:
			result = SML_DEVINF_SYNCTYPE_ONE_WAY_FROM_SERVER;
			break;
		case SML_DEVINF_SYNCTYPE_REFRESH_FROM_SERVER:
			result = SML_DEVINF_SYNCTYPE_REFRESH_FROM_SERVER;
			break;
		case SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC:
			result = SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC;
			break;
		default:
			smlErrorSet(error, SML_ERROR_GENERIC,
				"The synchronization type %u is unknwon.", id);
			smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
			return SML_DEVINF_SYNCTYPE_UNKNOWN;
			break;
	}
	smlTrace(TRACE_EXIT, "%s - %u", __func__, result);
	return result;
}

