/**
* \file ServiceName.c
* \brief Common API for dealing with allowed service names.
* \author Dmytro Podgornyi (d.podgornyi@samsung.com)
* \version 0.1
* \date Created Oct 07, 2013
* \par In Samsung Ukraine R&D Center (SURC) under a contract between
* \par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
* \par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
* \par Copyright: (c) Samsung Electronics Co, Ltd 2012. All rights reserved.
**/

/* for snprintf() */
#include <stdio.h>
#include <string.h>

#include "ServiceName.h"
#include "CommLayerData.h"

static const char *serviceNameBuildPath(const char * const name);
static void buildAllowedChar(void);
static void toLowerCase(char *s);

struct ServiceNameCtx
{
	const char *name;
	const char *path;
};

static struct ServiceNameCtx serviceNameTbl[] =
{
	/* designated initializers not supported by C89 */
	{"KNOX",  "/efs/prov_data/knox/knox.dat"},
	{"MLDAP", "/efs/prov_data/mldap/mldap.dat"},
	{"SD",    "/efs/prov_data/sd/sd.dat"},
#ifdef USE_NEW_POS_PATH
	{"DRK",   "/mnt/vendor/efs/prov_data/dev_root/dev_root.dat"},
#else
	{"DRK",   "/efs/prov_data/dev_root/dev_root.dat"},
#endif /* USE_NEW_POS_PATH */
	{"SK",    "/efs/prov_data/sk/sk.dat"},
};

static const char sfs_dir[] = "/efs/prov_data";
#define MAX_SFS_PATH (sizeof(sfs_dir) + MAX_SERVICE_NAME * 2 + 8)

static int allowedChar[256] = {0};
static int allowedCharInited = 0;

/**
 * Whether service name valid or not. Invalid names mustn't be used for
 * service key generation.
 * @param   [in] name Service name
 * @return  TRUE if service name is allowed and FALSE otherwise
 */
int serviceNameValid(const char * const name)
{
	size_t i = 0;
	size_t len = 0;

	len = strlen(name);
	if (len == 0 || len >= MAX_SERVICE_NAME) {
		return FALSE;
	}

	if (!allowedCharInited) {
		buildAllowedChar();
	}

	for (i = 0; i < len; i++) {
		if (!allowedChar[(unsigned char)name[i]]) {
			return FALSE;
		}
	}

	return TRUE;
}

/**
 * Get file path where service key is stored
 * @param   [in] name Service name
 * @return  String that represents absolute file path or NULL if error occurs
 */
const char *serviceNameGetPath(const char * const name)
{
	size_t i = 0;

	if (!serviceNameValid(name)) {
		return NULL;
	}

	for (i = 0; i < ARRAY_SIZE(serviceNameTbl); i++) {
		if (strcmp(name, serviceNameTbl[i].name) == 0) {
			return serviceNameTbl[i].path;
		}
	}

	return serviceNameBuildPath(name);
}

static const char *serviceNameBuildPath(const char * const name)
{
	static char buf[MAX_SFS_PATH] = {0};
	char service[MAX_SERVICE_NAME + 1] = {0};
	int i;

	strncpy(service, name, MAX_SERVICE_NAME);
	toLowerCase(service);
	
	memset(buf, 0, sizeof(buf));
	i = snprintf(buf, sizeof(buf), "%s/%s/%s.dat", sfs_dir, service, service);
	if (i < 0 || i >= (int)sizeof(buf)) {
		return NULL;
	}

	/* buf is static */
	return (const char *)buf;
}

static void buildAllowedChar(void)
{
	char c = '\0';

	for (c = 'a'; c <= 'z'; c++) {
		allowedChar[(unsigned char)c] = 1;
	}
	for (c = 'A'; c <= 'Z'; c++) {
		allowedChar[(unsigned char)c] = 1;
	}
	for (c = '0'; c <= '9'; c++) {
		allowedChar[(unsigned char)c] = 1;
	}
	allowedChar[(unsigned char)'_'] = 1;
	allowedChar[(unsigned char)'-'] = 1;
}

static void toLowerCase(char *s)
{
	size_t i = 0;
	size_t len = 0;

	len = strlen(s);
	for (i = 0; i < len; i++) {
		if (s[i] >= 'A' && s[i] <= 'Z') {
			s[i] += 'a' - 'A';
		}
	}
}