Blame channels/client/addin.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Channel Addins
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/file.h>
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/library.h>
Packit 1fb8d4
#include <winpr/collections.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/addin.h>
Packit 1fb8d4
#include <freerdp/build-config.h>
Packit 1fb8d4
#include <freerdp/client/channels.h>
Packit 1fb8d4
Packit 1fb8d4
#include "tables.h"
Packit 1fb8d4
Packit 1fb8d4
#include "addin.h"
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/channels/log.h>
Packit 1fb8d4
#define TAG CHANNELS_TAG("addin")
Packit 1fb8d4
Packit 1fb8d4
extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[];
Packit 1fb8d4
Packit 1fb8d4
void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table,
Packit 1fb8d4
        const char* identifier)
Packit 1fb8d4
{
Packit 1fb8d4
	int index = 0;
Packit 1fb8d4
	STATIC_ENTRY* pEntry;
Packit 1fb8d4
	pEntry = (STATIC_ENTRY*) &table->table[index++];
Packit 1fb8d4
Packit 1fb8d4
	while (pEntry->entry != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(pEntry->name, identifier) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			return (void*) pEntry->entry;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		pEntry = (STATIC_ENTRY*) &table->table[index++];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void* freerdp_channels_client_find_static_entry(const char* name, const char* identifier)
Packit 1fb8d4
{
Packit 1fb8d4
	int index = 0;
Packit 1fb8d4
	STATIC_ENTRY_TABLE* pEntry;
Packit 1fb8d4
	pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++];
Packit 1fb8d4
Packit 1fb8d4
	while (pEntry->table != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(pEntry->name, name) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			return freerdp_channels_find_static_entry_in_table(pEntry, identifier);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[];
Packit 1fb8d4
Packit 1fb8d4
FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR pszSubsystem,
Packit 1fb8d4
        LPSTR pszType, DWORD dwFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t i, j;
Packit 1fb8d4
	DWORD nAddins;
Packit 1fb8d4
	FREERDP_ADDIN** ppAddins = NULL;
Packit 1fb8d4
	STATIC_SUBSYSTEM_ENTRY* subsystems;
Packit 1fb8d4
	nAddins = 0;
Packit 1fb8d4
	ppAddins = (FREERDP_ADDIN**) calloc(128, sizeof(FREERDP_ADDIN*));
Packit 1fb8d4
Packit 1fb8d4
	if (!ppAddins)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ppAddins[nAddins] = NULL;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN));
Packit 1fb8d4
Packit 1fb8d4
		if (!pAddin)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
			goto error_out;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", CLIENT_STATIC_ADDIN_TABLE[i].name);
Packit 1fb8d4
		pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
Packit 1fb8d4
		pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
Packit 1fb8d4
		pAddin->dwFlags |= FREERDP_ADDIN_NAME;
Packit 1fb8d4
		ppAddins[nAddins++] = pAddin;
Packit 1fb8d4
		subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table;
Packit 1fb8d4
Packit 1fb8d4
		for (j = 0; subsystems[j].name != NULL; j++)
Packit 1fb8d4
		{
Packit 1fb8d4
			pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN));
Packit 1fb8d4
Packit 1fb8d4
			if (!pAddin)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
				goto error_out;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", CLIENT_STATIC_ADDIN_TABLE[i].name);
Packit 1fb8d4
			sprintf_s(pAddin->cSubsystem, ARRAYSIZE(pAddin->cSubsystem), "%s", subsystems[j].name);
Packit 1fb8d4
			pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_NAME;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
Packit 1fb8d4
			ppAddins[nAddins++] = pAddin;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return ppAddins;
Packit 1fb8d4
error_out:
Packit 1fb8d4
	freerdp_channels_addin_list_free(ppAddins);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSubsystem,
Packit 1fb8d4
        LPSTR pszType, DWORD dwFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	int nDashes;
Packit 1fb8d4
	HANDLE hFind;
Packit 1fb8d4
	DWORD nAddins;
Packit 1fb8d4
	LPSTR pszPattern;
Packit 1fb8d4
	size_t cchPattern;
Packit 1fb8d4
	LPCSTR pszAddinPath = FREERDP_ADDIN_PATH;
Packit 1fb8d4
	LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
Packit 1fb8d4
	LPCSTR pszExtension;
Packit 1fb8d4
	LPSTR pszSearchPath;
Packit 1fb8d4
	size_t cchSearchPath;
Packit 1fb8d4
	size_t cchAddinPath;
Packit 1fb8d4
	size_t cchInstallPrefix;
Packit 1fb8d4
	FREERDP_ADDIN** ppAddins;
Packit 1fb8d4
	WIN32_FIND_DATAA FindData;
Packit 1fb8d4
	cchAddinPath = strlen(pszAddinPath);
Packit 1fb8d4
	cchInstallPrefix = strlen(pszInstallPrefix);
Packit 1fb8d4
	pszExtension = PathGetSharedLibraryExtensionA(0);
Packit 1fb8d4
	cchPattern = 128 + strlen(pszExtension) + 2;
Packit 1fb8d4
	pszPattern = (LPSTR) malloc(cchPattern + 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!pszPattern)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "malloc failed!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pszName && pszSubsystem && pszType)
Packit 1fb8d4
	{
Packit 1fb8d4
		sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s",
Packit 1fb8d4
		          pszName, pszSubsystem, pszType, pszExtension);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pszName && pszType)
Packit 1fb8d4
	{
Packit 1fb8d4
		sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s",
Packit 1fb8d4
		          pszName, pszType, pszExtension);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pszName)
Packit 1fb8d4
	{
Packit 1fb8d4
		sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client*.%s",
Packit 1fb8d4
		          pszName, pszExtension);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"?-client*.%s",
Packit 1fb8d4
		          pszExtension);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	cchPattern = strlen(pszPattern);
Packit 1fb8d4
	cchSearchPath = cchInstallPrefix + cchAddinPath + cchPattern + 3;
Packit 1fb8d4
	pszSearchPath = (LPSTR) malloc(cchSearchPath + 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!pszSearchPath)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "malloc failed!");
Packit 1fb8d4
		free(pszPattern);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(pszSearchPath, pszInstallPrefix, cchInstallPrefix);
Packit 1fb8d4
	pszSearchPath[cchInstallPrefix] = '\0';
Packit 1fb8d4
	NativePathCchAppendA(pszSearchPath, cchSearchPath + 1, pszAddinPath);
Packit 1fb8d4
	NativePathCchAppendA(pszSearchPath, cchSearchPath + 1, pszPattern);
Packit 1fb8d4
	free(pszPattern);
Packit 1fb8d4
	hFind = FindFirstFileA(pszSearchPath, &FindData);
Packit 1fb8d4
	free(pszSearchPath);
Packit 1fb8d4
	nAddins = 0;
Packit 1fb8d4
	ppAddins = (FREERDP_ADDIN**) calloc(128, sizeof(FREERDP_ADDIN*));
Packit 1fb8d4
Packit 1fb8d4
	if (!ppAddins)
Packit 1fb8d4
	{
Packit 1fb8d4
		FindClose(hFind);
Packit 1fb8d4
		WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (hFind == INVALID_HANDLE_VALUE)
Packit 1fb8d4
		return ppAddins;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		char* p[5];
Packit 1fb8d4
		FREERDP_ADDIN* pAddin;
Packit 1fb8d4
		nDashes = 0;
Packit 1fb8d4
		pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN));
Packit 1fb8d4
Packit 1fb8d4
		if (!pAddin)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
			goto error_out;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		for (index = 0; FindData.cFileName[index]; index++)
Packit 1fb8d4
			nDashes += (FindData.cFileName[index] == '-') ? 1 : 0;
Packit 1fb8d4
Packit 1fb8d4
		if (nDashes == 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* <name>-client.<extension> */
Packit 1fb8d4
			p[0] = FindData.cFileName;
Packit 1fb8d4
			p[1] = strchr(p[0], '-') + 1;
Packit 1fb8d4
			strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
Packit 1fb8d4
			pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_NAME;
Packit 1fb8d4
			ppAddins[nAddins++] = pAddin;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (nDashes == 2)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* <name>-client-<subsystem>.<extension> */
Packit 1fb8d4
			p[0] = FindData.cFileName;
Packit 1fb8d4
			p[1] = strchr(p[0], '-') + 1;
Packit 1fb8d4
			p[2] = strchr(p[1], '-') + 1;
Packit 1fb8d4
			p[3] = strchr(p[2], '.') + 1;
Packit 1fb8d4
			strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
Packit 1fb8d4
			strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
Packit 1fb8d4
			pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_NAME;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
Packit 1fb8d4
			ppAddins[nAddins++] = pAddin;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (nDashes == 3)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* <name>-client-<subsystem>-<type>.<extension> */
Packit 1fb8d4
			p[0] = FindData.cFileName;
Packit 1fb8d4
			p[1] = strchr(p[0], '-') + 1;
Packit 1fb8d4
			p[2] = strchr(p[1], '-') + 1;
Packit 1fb8d4
			p[3] = strchr(p[2], '-') + 1;
Packit 1fb8d4
			p[4] = strchr(p[3], '.') + 1;
Packit 1fb8d4
			strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
Packit 1fb8d4
			strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
Packit 1fb8d4
			strncpy(pAddin->cType, p[3], (p[4] - p[3]) - 1);
Packit 1fb8d4
			pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_NAME;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
Packit 1fb8d4
			pAddin->dwFlags |= FREERDP_ADDIN_TYPE;
Packit 1fb8d4
			ppAddins[nAddins++] = pAddin;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			free(pAddin);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	while (FindNextFileA(hFind, &FindData));
Packit 1fb8d4
Packit 1fb8d4
	FindClose(hFind);
Packit 1fb8d4
	ppAddins[nAddins] = NULL;
Packit 1fb8d4
	return ppAddins;
Packit 1fb8d4
error_out:
Packit 1fb8d4
	FindClose(hFind);
Packit 1fb8d4
	freerdp_channels_addin_list_free(ppAddins);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
FREERDP_ADDIN** freerdp_channels_list_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType,
Packit 1fb8d4
        DWORD dwFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	if (dwFlags & FREERDP_ADDIN_STATIC)
Packit 1fb8d4
		return freerdp_channels_list_client_static_addins(pszName, pszSubsystem, pszType, dwFlags);
Packit 1fb8d4
	else if (dwFlags & FREERDP_ADDIN_DYNAMIC)
Packit 1fb8d4
		return freerdp_channels_list_dynamic_addins(pszName, pszSubsystem, pszType, dwFlags);
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
Packit 1fb8d4
	if (!ppAddins)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; ppAddins[index] != NULL; index++)
Packit 1fb8d4
		free(ppAddins[index]);
Packit 1fb8d4
Packit 1fb8d4
	free(ppAddins);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
extern const STATIC_ENTRY CLIENT_VirtualChannelEntryEx_TABLE[];
Packit 1fb8d4
Packit 1fb8d4
BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	STATIC_ENTRY* entry;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; CLIENT_VirtualChannelEntryEx_TABLE[i].name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		entry = (STATIC_ENTRY*) &CLIENT_VirtualChannelEntryEx_TABLE[i];
Packit 1fb8d4
Packit 1fb8d4
		if (!strcmp(entry->name, pszName))
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPSTR pszSubsystem,
Packit 1fb8d4
        LPSTR pszType, DWORD dwFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	int i, j;
Packit 1fb8d4
	STATIC_SUBSYSTEM_ENTRY* subsystems;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(CLIENT_STATIC_ADDIN_TABLE[i].name, pszName) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (pszSubsystem != NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table;
Packit 1fb8d4
Packit 1fb8d4
				for (j = 0; subsystems[j].name != NULL; j++)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (strcmp(subsystems[j].name, pszSubsystem) == 0)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (pszType)
Packit 1fb8d4
						{
Packit 1fb8d4
							if (strcmp(subsystems[j].type, pszType) == 0)
Packit 1fb8d4
								return (PVIRTUALCHANNELENTRY) subsystems[j].entry;
Packit 1fb8d4
						}
Packit 1fb8d4
						else
Packit 1fb8d4
						{
Packit 1fb8d4
							return (PVIRTUALCHANNELENTRY) subsystems[j].entry;
Packit 1fb8d4
						}
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (!freerdp_channels_is_virtual_channel_entry_ex(pszName))
Packit 1fb8d4
						return NULL;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				return (PVIRTUALCHANNELENTRY) CLIENT_STATIC_ADDIN_TABLE[i].entry;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}