/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS system libraries
 * FILE:            lib/smlib/lookupss.c
 */

#include "precomp.h"

#define NDEBUG
#include <debug.h>

/**********************************************************************
 * NAME							EXPORTED
 *	SmLookupSubsystem/6
 *
 * DESCRIPTION
 * 	Read from the registry key
 * 	\Registry\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems
 * 	the value which name is Name.
 *
 * ARGUMENTS
 * 	Name: name of the program to run, that is a value's name in
 * 	      the SM registry key SubSystems;
 * 	Data: what the registry gave back for Name;
 * 	DataLength: how much Data the registry returns;
 * 	DataType: what is Data?
 * 	Environment: set it if you want this function to use it
 * 	      to possibly expand Data before giving it back; if set
 * 	      to NULL, no expansion will be performed.
 */
NTSTATUS WINAPI
SmLookupSubsystem (IN     PWSTR   Name,
		   IN OUT PWSTR   Data,
		   IN OUT PULONG  DataLength,
		   IN OUT PULONG  DataType,
		   IN     PVOID   Environment OPTIONAL)
{
	NTSTATUS           Status = STATUS_SUCCESS;
	UNICODE_STRING     usKeyName = { 0, 0, NULL };
	OBJECT_ATTRIBUTES  Oa = {0};
	HANDLE             hKey = (HANDLE) 0;

	DPRINT("SM: %s(Name='%S') called\n", __FUNCTION__, Name);
	/*
	 * Prepare the key name to scan and
	 * related object attributes.
	 */
	RtlInitUnicodeString (& usKeyName,
		L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems");

	InitializeObjectAttributes (& Oa,
				    & usKeyName,
				    OBJ_CASE_INSENSITIVE,
				    NULL,
				    NULL);
	/*
	 * Open the key. This MUST NOT fail, if the
	 * request is for a legitimate subsystem.
	 */
	Status = NtOpenKey (& hKey,
			      MAXIMUM_ALLOWED,
			      & Oa);
	if(NT_SUCCESS(Status))
	{
		UNICODE_STRING usValueName = { 0, 0, NULL };
		PWCHAR         KeyValueInformation = NULL;
		ULONG          KeyValueInformationLength = 1024;
		ULONG          ResultLength = 0L;
		PKEY_VALUE_PARTIAL_INFORMATION kvpi = NULL;

		KeyValueInformation = RtlAllocateHeap (RtlGetProcessHeap(),
						       0,
						       KeyValueInformationLength);
		if (NULL == KeyValueInformation)
		{
			return STATUS_NO_MEMORY;
		}
		kvpi = (PKEY_VALUE_PARTIAL_INFORMATION) KeyValueInformation;
		RtlInitUnicodeString (& usValueName, Name);
		Status = NtQueryValueKey (hKey,
					  & usValueName,
					  KeyValuePartialInformation,
					  KeyValueInformation,
					  KeyValueInformationLength,
					  & ResultLength);
		if(NT_SUCCESS(Status))
		{
			DPRINT("nkvpi.TitleIndex = %lu\n", kvpi->TitleIndex);
			DPRINT("kvpi.Type        = %lu\n", kvpi->Type);
			DPRINT("kvpi.DataLength  = %lu\n", kvpi->DataLength);

			if((NULL != Data) && (NULL != DataLength) && (NULL != DataType))
			{
				*DataType = kvpi->Type;
				if((NULL != Environment) && (REG_EXPAND_SZ == *DataType))
				{
					UNICODE_STRING Source;
					PWCHAR         DestinationBuffer = NULL;
					UNICODE_STRING Destination;
					ULONG          Length = 0;

					DPRINT("SM: %s: value will be expanded\n", __FUNCTION__);

					DestinationBuffer = RtlAllocateHeap (RtlGetProcessHeap(),
									     0,
									     (2 * KeyValueInformationLength));
					if (NULL == DestinationBuffer)
					{
						Status = STATUS_NO_MEMORY;
					}
					else
					{
						Source.Length        = (USHORT)kvpi->DataLength;
						Source.MaximumLength = (USHORT)kvpi->DataLength;
						Source.Buffer        = (PWCHAR) & kvpi->Data;

						Destination.Length        = 0;
						Destination.MaximumLength = (USHORT)(2 * KeyValueInformationLength);
						Destination.Buffer        = DestinationBuffer;

						Status = RtlExpandEnvironmentStrings_U (Environment,
											& Source,
											& Destination,
											& Length);
						if(NT_SUCCESS(Status))
						{
							*DataLength = min(*DataLength, Destination.Length);
							RtlCopyMemory (Data, Destination.Buffer, *DataLength);
						}
						RtlFreeHeap (RtlGetProcessHeap(), 0, DestinationBuffer);
					}
				}else{
					DPRINT("SM: %s: value won't be expanded\n", __FUNCTION__);
					*DataLength = min(*DataLength, kvpi->DataLength);
					RtlCopyMemory (Data, & kvpi->Data, *DataLength);
				}
				*DataType = kvpi->Type;
			}else{
				DPRINT1("SM: %s: Data or DataLength or DataType is NULL!\n", __FUNCTION__);
				Status = STATUS_INVALID_PARAMETER;
			}
		}else{
			DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__, Status);
		}
		RtlFreeHeap (RtlGetProcessHeap(), 0, KeyValueInformation);
		NtClose (hKey);
	}else{
		DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__, Status);
	}
	return Status;
}

/* EOF */