[BASESRV-CONSRV-WINSRV]
[reactos.git] / win32ss / user / consrv / lineinput.c
index d3180d6..e778489 100644 (file)
@@ -1,33 +1,36 @@
 /*
- * PROJECT:         ReactOS CSRSS
  * LICENSE:         GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Console Server DLL
  * FILE:            win32ss/user/consrv/lineinput.c
  * PURPOSE:         Console line input functions
  * PROGRAMMERS:     Jeffrey Morlan
  */
 
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include "consrv.h"
+#include "console.h"
+#include "include/conio.h"
 #include "conio.h"
 
 #define NDEBUG
 #include <debug.h>
 
-typedef struct tagHISTORY_BUFFER
+typedef struct _HISTORY_BUFFER
 {
     LIST_ENTRY ListEntry;
-    WORD Position;
-    WORD MaxEntries;
-    WORD NumEntries;
+    UINT Position;
+    UINT MaxEntries;
+    UINT NumEntries;
     PUNICODE_STRING Entries;
     UNICODE_STRING ExeName;
 } HISTORY_BUFFER, *PHISTORY_BUFFER;
 
-/* FUNCTIONS *****************************************************************/
+
+/* PRIVATE FUNCTIONS **********************************************************/
 
 static PHISTORY_BUFFER
-HistoryCurrentBuffer(PCSRSS_CONSOLE Console)
+HistoryCurrentBuffer(PCONSOLE Console)
 {
     /* TODO: use actual EXE name sent from process that called ReadConsole */
     UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" };
@@ -42,15 +45,15 @@ HistoryCurrentBuffer(PCSRSS_CONSOLE Console)
     }
 
     /* Couldn't find the buffer, create a new one */
-    Hist = HeapAlloc(ConSrvHeap, 0, sizeof(HISTORY_BUFFER) + ExeName.Length);
+    Hist = RtlAllocateHeap(ConSrvHeap, 0, sizeof(HISTORY_BUFFER) + ExeName.Length);
     if (!Hist)
         return NULL;
     Hist->MaxEntries = Console->HistoryBufferSize;
     Hist->NumEntries = 0;
-    Hist->Entries = HeapAlloc(ConSrvHeap, 0, Hist->MaxEntries * sizeof(UNICODE_STRING));
+    Hist->Entries = RtlAllocateHeap(ConSrvHeap, 0, Hist->MaxEntries * sizeof(UNICODE_STRING));
     if (!Hist->Entries)
     {
-        HeapFree(ConSrvHeap, 0, Hist);
+        RtlFreeHeap(ConSrvHeap, 0, Hist);
         return NULL;
     }
     Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName.Length;
@@ -61,7 +64,7 @@ HistoryCurrentBuffer(PCSRSS_CONSOLE Console)
 }
 
 static VOID
-HistoryAddEntry(PCSRSS_CONSOLE Console)
+HistoryAddEntry(PCONSOLE Console)
 {
     UNICODE_STRING NewEntry;
     PHISTORY_BUFFER Hist;
@@ -113,7 +116,7 @@ HistoryAddEntry(PCSRSS_CONSOLE Console)
 }
 
 static VOID
-HistoryGetCurrentEntry(PCSRSS_CONSOLE Console, PUNICODE_STRING Entry)
+HistoryGetCurrentEntry(PCONSOLE Console, PUNICODE_STRING Entry)
 {
     PHISTORY_BUFFER Hist;
     if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
@@ -123,7 +126,7 @@ HistoryGetCurrentEntry(PCSRSS_CONSOLE Console, PUNICODE_STRING Entry)
 }
 
 static PHISTORY_BUFFER
-HistoryFindBuffer(PCSRSS_CONSOLE Console, PUNICODE_STRING ExeName)
+HistoryFindBuffer(PCONSOLE Console, PUNICODE_STRING ExeName)
 {
     PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
     while (Entry != &Console->HistoryBuffers)
@@ -137,217 +140,51 @@ HistoryFindBuffer(PCSRSS_CONSOLE Console, PUNICODE_STRING ExeName)
     return NULL;
 }
 
-VOID FASTCALL
+static VOID
 HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
 {
-    if (!Hist)
-        return;
+    if (!Hist) return;
+
     while (Hist->NumEntries != 0)
         RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
-    HeapFree(ConSrvHeap, 0, Hist->Entries);
-    RemoveEntryList(&Hist->ListEntry);
-    HeapFree(ConSrvHeap, 0, Hist);
-}
-
-CSR_API(SrvGetConsoleCommandHistoryLength)
-{
-    PCSRSS_GET_COMMAND_HISTORY_LENGTH GetCommandHistoryLength = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryLength;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    NTSTATUS Status;
-    PHISTORY_BUFFER Hist;
-    ULONG Length = 0;
-    INT i;
-
-    if (!Win32CsrValidateBuffer(ProcessData,
-                                GetCommandHistoryLength->ExeName.Buffer,
-                                GetCommandHistoryLength->ExeName.Length, 1))
-    {
-        return STATUS_ACCESS_VIOLATION;
-    }
-
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if (NT_SUCCESS(Status))
-    {
-        Hist = HistoryFindBuffer(Console, &GetCommandHistoryLength->ExeName);
-        if (Hist)
-        {
-            for (i = 0; i < Hist->NumEntries; i++)
-                Length += Hist->Entries[i].Length + sizeof(WCHAR);
-        }
-        GetCommandHistoryLength->Length = Length;
-        ConioUnlockConsole(Console);
-    }
-    return Status;
-}
-
-CSR_API(SrvGetConsoleCommandHistory)
-{
-    PCSRSS_GET_COMMAND_HISTORY GetCommandHistory = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistory;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    NTSTATUS Status;
-    PHISTORY_BUFFER Hist;
-    PBYTE Buffer = (PBYTE)GetCommandHistory->History;
-    ULONG BufferSize = GetCommandHistory->Length;
-    INT i;
-
-    if (!Win32CsrValidateBuffer(ProcessData, Buffer, BufferSize, 1) ||
-        !Win32CsrValidateBuffer(ProcessData,
-                                GetCommandHistory->ExeName.Buffer,
-                                GetCommandHistory->ExeName.Length, 1))
-    {
-        return STATUS_ACCESS_VIOLATION;
-    }
-
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if (NT_SUCCESS(Status))
-    {
-        Hist = HistoryFindBuffer(Console, &GetCommandHistory->ExeName);
-        if (Hist)
-        {
-            for (i = 0; i < Hist->NumEntries; i++)
-            {
-                if (BufferSize < (Hist->Entries[i].Length + sizeof(WCHAR)))
-                {
-                    Status = STATUS_BUFFER_OVERFLOW;
-                    break;
-                }
-                memcpy(Buffer, Hist->Entries[i].Buffer, Hist->Entries[i].Length);
-                Buffer += Hist->Entries[i].Length;
-                *(PWCHAR)Buffer = L'\0';
-                Buffer += sizeof(WCHAR);
-            }
-        }
-        GetCommandHistory->Length = Buffer - (PBYTE)GetCommandHistory->History;
-        ConioUnlockConsole(Console);
-    }
-    return Status;
-}
-
-CSR_API(SrvExpungeConsoleCommandHistory)
-{
-    PCSRSS_EXPUNGE_COMMAND_HISTORY ExpungeCommandHistory = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ExpungeCommandHistory;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    PHISTORY_BUFFER Hist;
-    NTSTATUS Status;
-
-    if (!Win32CsrValidateBuffer(ProcessData,
-                                ExpungeCommandHistory->ExeName.Buffer,
-                                ExpungeCommandHistory->ExeName.Length, 1))
-    {
-        return STATUS_ACCESS_VIOLATION;
-    }
-
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if (NT_SUCCESS(Status))
-    {
-        Hist = HistoryFindBuffer(Console, &ExpungeCommandHistory->ExeName);
-        HistoryDeleteBuffer(Hist);
-        ConioUnlockConsole(Console);
-    }
-    return Status;
-}
-
-CSR_API(SrvSetConsoleNumberOfCommands)
-{
-    PCSRSS_SET_HISTORY_NUMBER_COMMANDS SetHistoryNumberCommands = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryNumberCommands;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    PHISTORY_BUFFER Hist;
-    NTSTATUS Status;
-    WORD MaxEntries = SetHistoryNumberCommands->NumCommands;
-    PUNICODE_STRING OldEntryList, NewEntryList;
-
-    if (!Win32CsrValidateBuffer(ProcessData,
-                                SetHistoryNumberCommands->ExeName.Buffer,
-                                SetHistoryNumberCommands->ExeName.Length, 1))
-    {
-        return STATUS_ACCESS_VIOLATION;
-    }
-
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if (NT_SUCCESS(Status))
-    {
-        Hist = HistoryFindBuffer(Console, &SetHistoryNumberCommands->ExeName);
-        if (Hist)
-        {
-            OldEntryList = Hist->Entries;
-            NewEntryList = HeapAlloc(ConSrvHeap, 0,
-                                     MaxEntries * sizeof(UNICODE_STRING));
-            if (!NewEntryList)
-            {
-                Status = STATUS_NO_MEMORY;
-            }
-            else
-            {
-                /* If necessary, shrink by removing oldest entries */
-                for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
-                {
-                    RtlFreeUnicodeString(Hist->Entries++);
-                    Hist->Position += (Hist->Position == 0);
-                }
 
-                Hist->MaxEntries = MaxEntries;
-                Hist->Entries = memcpy(NewEntryList, Hist->Entries,
-                                       Hist->NumEntries * sizeof(UNICODE_STRING));
-                HeapFree(ConSrvHeap, 0, OldEntryList);
-            }
-        }
-        ConioUnlockConsole(Console);
-    }
-    return Status;
+    RtlFreeHeap(ConSrvHeap, 0, Hist->Entries);
+    RemoveEntryList(&Hist->ListEntry);
+    RtlFreeHeap(ConSrvHeap, 0, Hist);
 }
 
-CSR_API(SrvGetConsoleHistory)
+VOID FASTCALL
+HistoryDeleteBuffers(PCONSOLE Console)
 {
-    PCSRSS_GET_HISTORY_INFO GetHistoryInfo = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetHistoryInfo;
-    PCSRSS_CONSOLE Console;
-    NTSTATUS Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (NT_SUCCESS(Status))
-    {
-        GetHistoryInfo->HistoryBufferSize      = Console->HistoryBufferSize;
-        GetHistoryInfo->NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
-        GetHistoryInfo->dwFlags                = Console->HistoryNoDup;
-        ConioUnlockConsole(Console);
-    }
-    return Status;
-}
+    PLIST_ENTRY CurrentEntry;
+    PHISTORY_BUFFER HistoryBuffer;
 
-CSR_API(SrvSetConsoleHistory)
-{
-    PCSRSS_SET_HISTORY_INFO SetHistoryInfo = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryInfo;
-    PCSRSS_CONSOLE Console;
-    NTSTATUS Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (NT_SUCCESS(Status))
+    while (!IsListEmpty(&Console->HistoryBuffers))
     {
-        Console->HistoryBufferSize      = (WORD)SetHistoryInfo->HistoryBufferSize;
-        Console->NumberOfHistoryBuffers = (WORD)SetHistoryInfo->NumberOfHistoryBuffers;
-        Console->HistoryNoDup           = SetHistoryInfo->dwFlags & HISTORY_NO_DUP_FLAG;
-        ConioUnlockConsole(Console);
+        CurrentEntry = RemoveHeadList(&Console->HistoryBuffers);
+        HistoryBuffer = CONTAINING_RECORD(CurrentEntry, HISTORY_BUFFER, ListEntry);
+        HistoryDeleteBuffer(HistoryBuffer);
     }
-    return Status;
 }
 
 static VOID
-LineInputSetPos(PCSRSS_CONSOLE Console, UINT Pos)
+LineInputSetPos(PCONSOLE Console, UINT Pos)
 {
-    if (Pos != Console->LinePos && Console->Mode & ENABLE_ECHO_INPUT)
+    if (Pos != Console->LinePos && Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
     {
-        PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
-        UINT OldCursorX = Buffer->CurrentX;
-        UINT OldCursorY = Buffer->CurrentY;
-        INT XY = OldCursorY * Buffer->MaxX + OldCursorX;
+        PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
+        UINT OldCursorX = Buffer->CursorPosition.X;
+        UINT OldCursorY = Buffer->CursorPosition.Y;
+        INT XY = OldCursorY * Buffer->ScreenBufferSize.X + OldCursorX;
 
         XY += (Pos - Console->LinePos);
         if (XY < 0)
             XY = 0;
-        else if (XY >= Buffer->MaxY * Buffer->MaxX)
-            XY = Buffer->MaxY * Buffer->MaxX - 1;
+        else if (XY >= Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X)
+            XY = Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X - 1;
 
-        Buffer->CurrentX = XY % Buffer->MaxX;
-        Buffer->CurrentY = XY / Buffer->MaxX;
+        Buffer->CursorPosition.X = XY % Buffer->ScreenBufferSize.X;
+        Buffer->CursorPosition.Y = XY / Buffer->ScreenBufferSize.X;
         ConioSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
     }
 
@@ -355,7 +192,7 @@ LineInputSetPos(PCSRSS_CONSOLE Console, UINT Pos)
 }
 
 static VOID
-LineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Insertion)
+LineInputEdit(PCONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Insertion)
 {
     UINT Pos = Console->LinePos;
     UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
@@ -370,7 +207,7 @@ LineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR
             (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
     memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
 
-    if (Console->Mode & ENABLE_ECHO_INPUT)
+    if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
     {
         for (i = Pos; i < NewSize; i++)
         {
@@ -392,7 +229,7 @@ LineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR
 }
 
 static VOID
-LineInputRecallHistory(PCSRSS_CONSOLE Console, INT Offset)
+LineInputRecallHistory(PCONSOLE Console, INT Offset)
 {
     PHISTORY_BUFFER Hist;
 
@@ -411,7 +248,7 @@ LineInputRecallHistory(PCSRSS_CONSOLE Console, INT Offset)
 }
 
 VOID FASTCALL
-LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
+LineInputKeyDown(PCONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
 {
     UINT Pos = Console->LinePos;
     PHISTORY_BUFFER Hist;
@@ -552,7 +389,7 @@ LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
         return;
     }
 
-    if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->Mode & ENABLE_PROCESSED_INPUT)
+    if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT)
     {
         /* backspace handling - if processed input enabled then we handle it here
          * otherwise we treat it like a normal char. */
@@ -570,17 +407,17 @@ LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
 
         LineInputSetPos(Console, Console->LineSize);
         Console->LineBuffer[Console->LineSize++] = L'\r';
-        if (Console->Mode & ENABLE_ECHO_INPUT)
+        if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
             ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1, TRUE);
 
         /* Add \n if processed input. There should usually be room for it,
          * but an exception to the rule exists: the buffer could have been 
          * pre-filled with LineMaxSize - 1 characters. */
-        if (Console->Mode & ENABLE_PROCESSED_INPUT &&
+        if (Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
             Console->LineSize < Console->LineMaxSize)
         {
             Console->LineBuffer[Console->LineSize++] = L'\n';
-            if (Console->Mode & ENABLE_ECHO_INPUT)
+            if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
                 ConioWriteConsole(Console, Console->ActiveBuffer, "\n", 1, TRUE);
         }
         Console->LineComplete = TRUE;
@@ -606,4 +443,195 @@ LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
     }
 }
 
+
+/* PUBLIC SERVER APIS *********************************************************/
+
+CSR_API(SrvGetConsoleCommandHistory)
+{
+    PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCONSOLE Console;
+    NTSTATUS Status;
+    PHISTORY_BUFFER Hist;
+    PBYTE Buffer = (PBYTE)GetCommandHistoryRequest->History;
+    ULONG BufferSize = GetCommandHistoryRequest->Length;
+    INT i;
+
+    if ( !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&GetCommandHistoryRequest->History,
+                                   GetCommandHistoryRequest->Length,
+                                   sizeof(BYTE))                    ||
+         !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&GetCommandHistoryRequest->ExeName.Buffer,
+                                   GetCommandHistoryRequest->ExeName.Length,
+                                   sizeof(BYTE)) )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        Hist = HistoryFindBuffer(Console, &GetCommandHistoryRequest->ExeName);
+        if (Hist)
+        {
+            for (i = 0; i < Hist->NumEntries; i++)
+            {
+                if (BufferSize < (Hist->Entries[i].Length + sizeof(WCHAR)))
+                {
+                    Status = STATUS_BUFFER_OVERFLOW;
+                    break;
+                }
+                memcpy(Buffer, Hist->Entries[i].Buffer, Hist->Entries[i].Length);
+                Buffer += Hist->Entries[i].Length;
+                *(PWCHAR)Buffer = L'\0';
+                Buffer += sizeof(WCHAR);
+            }
+        }
+        GetCommandHistoryRequest->Length = Buffer - (PBYTE)GetCommandHistoryRequest->History;
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+}
+
+CSR_API(SrvGetConsoleCommandHistoryLength)
+{
+    PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryLengthRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCONSOLE Console;
+    NTSTATUS Status;
+    PHISTORY_BUFFER Hist;
+    ULONG Length = 0;
+    INT i;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&GetCommandHistoryLengthRequest->ExeName.Buffer,
+                                  GetCommandHistoryLengthRequest->ExeName.Length,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        Hist = HistoryFindBuffer(Console, &GetCommandHistoryLengthRequest->ExeName);
+        if (Hist)
+        {
+            for (i = 0; i < Hist->NumEntries; i++)
+                Length += Hist->Entries[i].Length + sizeof(WCHAR);
+        }
+        GetCommandHistoryLengthRequest->Length = Length;
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+}
+
+CSR_API(SrvExpungeConsoleCommandHistory)
+{
+    PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ExpungeCommandHistoryRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCONSOLE Console;
+    PHISTORY_BUFFER Hist;
+    NTSTATUS Status;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&ExpungeCommandHistoryRequest->ExeName.Buffer,
+                                  ExpungeCommandHistoryRequest->ExeName.Length,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        Hist = HistoryFindBuffer(Console, &ExpungeCommandHistoryRequest->ExeName);
+        HistoryDeleteBuffer(Hist);
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+}
+
+CSR_API(SrvSetConsoleNumberOfCommands)
+{
+    PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryNumberCommandsRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCONSOLE Console;
+    PHISTORY_BUFFER Hist;
+    NTSTATUS Status;
+    UINT MaxEntries = SetHistoryNumberCommandsRequest->NumCommands;
+    PUNICODE_STRING OldEntryList, NewEntryList;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&SetHistoryNumberCommandsRequest->ExeName.Buffer,
+                                  SetHistoryNumberCommandsRequest->ExeName.Length,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        Hist = HistoryFindBuffer(Console, &SetHistoryNumberCommandsRequest->ExeName);
+        if (Hist)
+        {
+            OldEntryList = Hist->Entries;
+            NewEntryList = RtlAllocateHeap(ConSrvHeap, 0,
+                                           MaxEntries * sizeof(UNICODE_STRING));
+            if (!NewEntryList)
+            {
+                Status = STATUS_NO_MEMORY;
+            }
+            else
+            {
+                /* If necessary, shrink by removing oldest entries */
+                for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
+                {
+                    RtlFreeUnicodeString(Hist->Entries++);
+                    Hist->Position += (Hist->Position == 0);
+                }
+
+                Hist->MaxEntries = MaxEntries;
+                Hist->Entries = memcpy(NewEntryList, Hist->Entries,
+                                       Hist->NumEntries * sizeof(UNICODE_STRING));
+                RtlFreeHeap(ConSrvHeap, 0, OldEntryList);
+            }
+        }
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+}
+
+CSR_API(SrvGetConsoleHistory)
+{
+    PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
+    PCONSOLE Console;
+    NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        HistoryInfoRequest->HistoryBufferSize      = Console->HistoryBufferSize;
+        HistoryInfoRequest->NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
+        HistoryInfoRequest->dwFlags                = Console->HistoryNoDup;
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+}
+
+CSR_API(SrvSetConsoleHistory)
+{
+    PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
+    PCONSOLE Console;
+    NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        Console->HistoryBufferSize      = HistoryInfoRequest->HistoryBufferSize;
+        Console->NumberOfHistoryBuffers = HistoryInfoRequest->NumberOfHistoryBuffers;
+        Console->HistoryNoDup           = HistoryInfoRequest->dwFlags & HISTORY_NO_DUP_FLAG;
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+}
+
 /* EOF */