#include <stdio.h>
#include <string.h>
#include "em_common.h"

int em_client_verify(em_context *ctx, em_parsed_token *parsed_token)
{
	int ret;

	ext_type_header head_data = {0,};
	char type_data[EM_EXT_TYPE_DATA_MAX] = {0,};

	char **type_item_data = NULL;
	char *client_item = NULL;
	em_client *client_data = NULL;

	int i;
	uint32_t converted_uid = 0;
	char allowed_uid[EM_LEN_CLIENT_UID+1] = {0,};
	int compare_len;

	EM_CHECK_NULL(__func__, EM_ERR_EM_CLIENT_VERIFY, ctx, parsed_token);

	memcpy(&converted_uid, &ctx->client_uid, sizeof(uint32_t));
	LOGI("Requested mode %0x\n", ctx->modes[0]);
	LOGI("Client process(%s), package(%s)\n", ctx->client_proc_name, ctx->client_pkg_name);
	LOGI("Client uid(%u), platgorm sig(%u)\n", converted_uid, ctx->client_signature);

	ret = em_get_from_extension(EM_EXT_TYPE_CLIENT, ctx->modes[0], parsed_token, &head_data, type_data);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get from extension\n");
		goto out;
	}

	if (memcmp(EM_EXT_TYPE_CLIENT, type_data, strlen(EM_EXT_TYPE_CLIENT))) {
		LOGE("Invaild client type data\n");
		ret = EM_ERR_EM_CLIENT_VERIFY_INVALID_CLIENT_TYPE;
		goto out;
	}

	if (head_data.num_of_data <= 0) {
		LOGE("Empty data\n");
		ret = EM_ERR_EM_CLIENT_VERIFY_EMPTY_DATA;
		goto out;
	}

	type_item_data = em_calloc(sizeof(char *), head_data.num_of_data);
	if (type_item_data == NULL) {
		LOGE("Failed to allocate type_item_data\n");
		ret = EM_ERR_EM_CLIENT_VERIFY_ALLOC_TYPE_ITEM_DATA;
		goto out;
	}

	strtok(type_data, EM_EXT_DELIMITER_ITEM);
	for (i = 0; i < head_data.num_of_data; i++) {
		type_item_data[i] = strtok(NULL, EM_EXT_DELIMITER_ITEM);
		LOGD("Client#%u : %s\n", i, type_item_data[i]);
	}

	client_data = em_calloc(sizeof(em_client), head_data.num_of_data);
	if (client_data == NULL) {
		LOGE("Failed to allocate client_data\n");
		ret = EM_ERR_EM_CLIENT_VERIFY_ALLOC_CLIENT_DATA;
		goto out;
	}

	ret = EM_ERR_EM_CLIENT_VERIFY_NO_PERMISSION;
	for (i = 0; i < head_data.num_of_data; i++) {
		client_item = strtok(type_item_data[i], EM_EXT_DELIMITER_DATA);
		memcpy(client_data[i].name, client_item, strlen(client_item));
		LOGD("name : %s\n", client_data[i].name);

		client_item = strtok(NULL, EM_EXT_DELIMITER_DATA);
		memcpy(client_data[i].uid, client_item, strlen(client_item));
		LOGD("uid : %s(%u)\n", client_data[i].uid, em_atoi(client_data[i].uid));

		client_item = strtok(NULL, EM_EXT_DELIMITER_DATA);
		memcpy(client_data[i].sig, client_item, strlen(client_item));
		LOGD("sig : %s\n", client_data[i].sig);

		/* Check em client */
		compare_len = strlen((const char *)client_data[i].name) > strlen((const char *)ctx->client_pkg_name)
				  ? strlen((const char *)ctx->client_pkg_name)
				  : strlen((const char *)client_data[i].name);
		if (memcmp(client_data[i].name, ctx->client_pkg_name, compare_len) ||
		    strlen((const char *)client_data[i].name) != strlen((const char *)ctx->client_pkg_name)) {
			compare_len =
			    strlen((const char *)client_data[i].name) > strlen((const char *)ctx->client_proc_name)
				? strlen((const char *)ctx->client_proc_name)
				: strlen((const char *)client_data[i].name);
			if (memcmp(client_data[i].name, ctx->client_proc_name, compare_len) ||
			    strlen((const char *)ctx->client_proc_name) != strlen((const char *)client_data[i].name)) {
				LOGE("Failed to check pkg name or proc name\n");
				continue;
			}
		}

		memcpy(allowed_uid, client_data[i].uid, EM_LEN_CLIENT_UID);
		if (((uint32_t)em_atoi(allowed_uid) != converted_uid) &&
		    memcmp(client_data[i].uid, EM_CLIENT_NNTC_UID, EM_LEN_CLIENT_UID)) {
			LOGE("Failed to check UID (%u/%u)\n", em_atoi(allowed_uid), converted_uid);
			continue;
		}

		if (!memcmp(client_data[i].sig, "pSig", 4) && !(ctx->client_signature == 0)) {
			LOGE("Failed to check Sig\n");
			break;
		}

		ret = EM_SUCCESS;
		break;
	}

out:
	if (type_item_data)
		em_free(type_item_data);

	if (client_data)
		em_free(client_data);

	if (ret != EM_SUCCESS)
		LOGI("Caller is not EM Client\n");
	else
		LOGE("Caller is EM Client\n");

	return ret;
}
