xref: /reactos/win32ss/user/winsrv/consrv/history.c (revision 92611107)
1 /*
2  * LICENSE:         GPL - See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/history.c
5  * PURPOSE:         Console line input functions
6  * PROGRAMMERS:     Jeffrey Morlan
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "consrv.h"
12 #include "popup.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 typedef struct _HISTORY_BUFFER
18 {
19     LIST_ENTRY ListEntry;
20     ULONG Position;
21     ULONG MaxEntries;
22     ULONG NumEntries;
23     UNICODE_STRING  ExeName;
24     PUNICODE_STRING Entries;
25 } HISTORY_BUFFER, *PHISTORY_BUFFER;
26 
27 
28 BOOLEAN
29 ConvertInputAnsiToUnicode(PCONSRV_CONSOLE Console,
30                           PVOID    Source,
31                           USHORT   SourceLength,
32                           // BOOLEAN  IsUnicode,
33                           PWCHAR*  Target,
34                           PUSHORT  TargetLength);
35 BOOLEAN
36 ConvertInputUnicodeToAnsi(PCONSRV_CONSOLE Console,
37                           PVOID    Source,
38                           USHORT   SourceLength,
39                           // BOOLEAN  IsAnsi,
40                           PCHAR/* * */   Target,
41                           /*P*/USHORT  TargetLength);
42 
43 
44 /* PRIVATE FUNCTIONS **********************************************************/
45 
46 static PHISTORY_BUFFER
HistoryCurrentBuffer(IN PCONSRV_CONSOLE Console,IN PUNICODE_STRING ExeName)47 HistoryCurrentBuffer(
48     IN PCONSRV_CONSOLE Console,
49     IN PUNICODE_STRING ExeName)
50 {
51     PLIST_ENTRY Entry;
52     PHISTORY_BUFFER Hist;
53 
54     for (Entry = Console->HistoryBuffers.Flink;
55          Entry != &Console->HistoryBuffers;
56          Entry = Entry->Flink)
57     {
58         Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
59         if (RtlEqualUnicodeString(ExeName, &Hist->ExeName, FALSE))
60             return Hist;
61     }
62 
63     /* Could not find the buffer, create a new one */
64 
65     if (Console->NumberOfHistoryBuffers < Console->MaxNumberOfHistoryBuffers)
66     {
67         Hist = ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER) + ExeName->Length);
68         if (!Hist) return NULL;
69         Hist->MaxEntries = Console->HistoryBufferSize;
70         Hist->NumEntries = 0;
71         Hist->Entries = ConsoleAllocHeap(0, Hist->MaxEntries * sizeof(UNICODE_STRING));
72         if (!Hist->Entries)
73         {
74             ConsoleFreeHeap(Hist);
75             return NULL;
76         }
77         Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName->Length;
78         Hist->ExeName.Buffer = (PWCHAR)(Hist + 1);
79         RtlCopyMemory(Hist->ExeName.Buffer, ExeName->Buffer, ExeName->Length);
80         InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
81         Console->NumberOfHistoryBuffers++;
82         return Hist;
83     }
84     else
85     {
86         // FIXME: TODO !!!!!!!
87         // Reuse an older history buffer, if possible with the same Exe name,
88         // otherwise take the oldest one and reset its contents.
89         // And move the history buffer back to the head of the list.
90         UNIMPLEMENTED;
91         return NULL;
92     }
93 }
94 
95 static PHISTORY_BUFFER
HistoryFindBuffer(PCONSRV_CONSOLE Console,PVOID ExeName,USHORT ExeLength,BOOLEAN UnicodeExe)96 HistoryFindBuffer(PCONSRV_CONSOLE Console,
97                   PVOID    ExeName,
98                   USHORT   ExeLength,
99                   BOOLEAN  UnicodeExe)
100 {
101     UNICODE_STRING ExeNameU;
102 
103     PLIST_ENTRY Entry;
104     PHISTORY_BUFFER Hist = NULL;
105 
106     if (ExeName == NULL) return NULL;
107 
108     if (UnicodeExe)
109     {
110         ExeNameU.Buffer = ExeName;
111         /* Length is in bytes */
112         ExeNameU.MaximumLength = ExeLength;
113     }
114     else
115     {
116         if (!ConvertInputAnsiToUnicode(Console,
117                                        ExeName, ExeLength,
118                                        &ExeNameU.Buffer, &ExeNameU.MaximumLength))
119         {
120             return NULL;
121         }
122     }
123     ExeNameU.Length = ExeNameU.MaximumLength;
124 
125     for (Entry = Console->HistoryBuffers.Flink;
126          Entry != &Console->HistoryBuffers;
127          Entry = Entry->Flink)
128     {
129         Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
130 
131         /* For the history APIs, the caller is allowed to give only part of the name */
132         if (RtlPrefixUnicodeString(&ExeNameU, &Hist->ExeName, TRUE))
133         {
134             if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
135             return Hist;
136         }
137     }
138 
139     if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
140     return NULL;
141 }
142 
143 static VOID
HistoryDeleteBuffer(PHISTORY_BUFFER Hist)144 HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
145 {
146     if (!Hist) return;
147 
148     while (Hist->NumEntries != 0)
149         RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
150 
151     ConsoleFreeHeap(Hist->Entries);
152     RemoveEntryList(&Hist->ListEntry);
153     ConsoleFreeHeap(Hist);
154 }
155 
156 static NTSTATUS
HistoryResizeBuffer(IN PHISTORY_BUFFER Hist,IN ULONG NumCommands)157 HistoryResizeBuffer(
158     IN PHISTORY_BUFFER Hist,
159     IN ULONG NumCommands)
160 {
161     PUNICODE_STRING OldEntryList = Hist->Entries;
162     PUNICODE_STRING NewEntryList;
163 
164     NewEntryList = ConsoleAllocHeap(0, NumCommands * sizeof(UNICODE_STRING));
165     if (!NewEntryList)
166         return STATUS_NO_MEMORY;
167 
168     /* If necessary, shrink by removing oldest entries */
169     for (; Hist->NumEntries > NumCommands; Hist->NumEntries--)
170     {
171         RtlFreeUnicodeString(Hist->Entries++);
172         Hist->Position += (Hist->Position == 0);
173     }
174 
175     Hist->MaxEntries = NumCommands;
176     RtlCopyMemory(NewEntryList, Hist->Entries,
177                   Hist->NumEntries * sizeof(UNICODE_STRING));
178     Hist->Entries = NewEntryList;
179     ConsoleFreeHeap(OldEntryList);
180 
181     return STATUS_SUCCESS;
182 }
183 
184 VOID
HistoryAddEntry(PCONSRV_CONSOLE Console,PUNICODE_STRING ExeName,PUNICODE_STRING Entry)185 HistoryAddEntry(PCONSRV_CONSOLE Console,
186                 PUNICODE_STRING ExeName,
187                 PUNICODE_STRING Entry)
188 {
189     // UNICODE_STRING NewEntry;
190     PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
191 
192     if (!Hist) return;
193 
194     // NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
195     // NewEntry.Buffer = Console->LineBuffer;
196 
197     /* Don't add blank or duplicate entries */
198     if (Entry->Length == 0 || Hist->MaxEntries == 0 ||
199         (Hist->NumEntries > 0 &&
200          RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1], Entry, FALSE)))
201     {
202         return;
203     }
204 
205     if (Console->HistoryNoDup)
206     {
207         INT i;
208 
209         /* Check if this line has been entered before */
210         for (i = Hist->NumEntries - 1; i >= 0; i--)
211         {
212             if (RtlEqualUnicodeString(&Hist->Entries[i], Entry, FALSE))
213             {
214                 UNICODE_STRING NewEntry;
215 
216                 /* Just rotate the list to bring this entry to the end */
217                 NewEntry = Hist->Entries[i];
218                 RtlMoveMemory(&Hist->Entries[i], &Hist->Entries[i + 1],
219                               (Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
220                 Hist->Entries[Hist->NumEntries - 1] = NewEntry;
221                 Hist->Position = Hist->NumEntries - 1;
222                 return;
223             }
224         }
225     }
226 
227     if (Hist->NumEntries == Hist->MaxEntries)
228     {
229         /* List is full, remove oldest entry */
230         RtlFreeUnicodeString(&Hist->Entries[0]);
231         RtlMoveMemory(&Hist->Entries[0], &Hist->Entries[1],
232                       --Hist->NumEntries * sizeof(UNICODE_STRING));
233     }
234 
235     if (NT_SUCCESS(RtlDuplicateUnicodeString(0, Entry, &Hist->Entries[Hist->NumEntries])))
236         Hist->NumEntries++;
237     Hist->Position = Hist->NumEntries - 1;
238 }
239 
240 VOID
HistoryGetCurrentEntry(PCONSRV_CONSOLE Console,PUNICODE_STRING ExeName,PUNICODE_STRING Entry)241 HistoryGetCurrentEntry(PCONSRV_CONSOLE Console,
242                        PUNICODE_STRING ExeName,
243                        PUNICODE_STRING Entry)
244 {
245     PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
246 
247     if (!Hist || Hist->NumEntries == 0)
248         Entry->Length = 0;
249     else
250         *Entry = Hist->Entries[Hist->Position];
251 }
252 
253 BOOL
HistoryRecallHistory(PCONSRV_CONSOLE Console,PUNICODE_STRING ExeName,INT Offset,PUNICODE_STRING Entry)254 HistoryRecallHistory(PCONSRV_CONSOLE Console,
255                      PUNICODE_STRING ExeName,
256                      INT Offset,
257                      PUNICODE_STRING Entry)
258 {
259     PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
260     ULONG Position = 0;
261 
262     if (!Hist || Hist->NumEntries == 0) return FALSE;
263 
264     Position = Hist->Position + Offset;
265     Position = min(max(Position, 0), Hist->NumEntries - 1);
266     Hist->Position = Position;
267 
268     *Entry = Hist->Entries[Hist->Position];
269     return TRUE;
270 }
271 
272 BOOL
HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console,PUNICODE_STRING ExeName,PUNICODE_STRING Prefix,PUNICODE_STRING Entry)273 HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console,
274                          PUNICODE_STRING ExeName,
275                          PUNICODE_STRING Prefix,
276                          PUNICODE_STRING Entry)
277 {
278     INT HistPos;
279 
280     /* Search for history entries starting with input. */
281     PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
282     if (!Hist || Hist->NumEntries == 0) return FALSE;
283 
284     /*
285      * Like Up/F5, on first time start from current (usually last) entry,
286      * but on subsequent times start at previous entry.
287      */
288     if (Console->LineUpPressed)
289         Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
290     Console->LineUpPressed = TRUE;
291 
292     // Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
293     // Entry.Buffer = Console->LineBuffer;
294 
295     /*
296      * Keep going backwards, even wrapping around to the end,
297      * until we get back to starting point.
298      */
299     HistPos = Hist->Position;
300     do
301     {
302         if (RtlPrefixUnicodeString(Prefix, &Hist->Entries[HistPos], FALSE))
303         {
304             Hist->Position = HistPos;
305             *Entry = Hist->Entries[HistPos];
306             return TRUE;
307         }
308         if (--HistPos < 0) HistPos += Hist->NumEntries;
309     } while (HistPos != Hist->Position);
310 
311     return FALSE;
312 }
313 
314 PPOPUP_WINDOW
HistoryDisplayCurrentHistory(PCONSRV_CONSOLE Console,PUNICODE_STRING ExeName)315 HistoryDisplayCurrentHistory(PCONSRV_CONSOLE Console,
316                              PUNICODE_STRING ExeName)
317 {
318     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
319     PPOPUP_WINDOW Popup;
320 
321     SHORT xLeft, yTop;
322     SHORT Width, Height;
323 
324     PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
325 
326     if (!Hist) return NULL;
327     if (Hist->NumEntries == 0) return NULL;
328 
329     if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) return NULL;
330     ActiveBuffer = Console->ActiveBuffer;
331 
332     Width  = 40;
333     Height = 10;
334 
335     /* Center the popup window on the screen */
336     xLeft = ActiveBuffer->ViewOrigin.X + (ActiveBuffer->ViewSize.X - Width ) / 2;
337     yTop  = ActiveBuffer->ViewOrigin.Y + (ActiveBuffer->ViewSize.Y - Height) / 2;
338 
339     /* Create the popup */
340     Popup = CreatePopupWindow(Console, ActiveBuffer,
341                               xLeft, yTop, Width, Height);
342     if (Popup == NULL) return NULL;
343 
344     Popup->PopupInputRoutine = NULL;
345 
346     return Popup;
347 }
348 
349 VOID
HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console,PUNICODE_STRING ExeName)350 HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console,
351                            PUNICODE_STRING ExeName)
352 {
353     HistoryDeleteBuffer(HistoryCurrentBuffer(Console, ExeName));
354 }
355 
356 VOID
HistoryDeleteBuffers(PCONSRV_CONSOLE Console)357 HistoryDeleteBuffers(PCONSRV_CONSOLE Console)
358 {
359     PLIST_ENTRY CurrentEntry;
360     PHISTORY_BUFFER HistoryBuffer;
361 
362     while (!IsListEmpty(&Console->HistoryBuffers))
363     {
364         CurrentEntry = RemoveHeadList(&Console->HistoryBuffers);
365         HistoryBuffer = CONTAINING_RECORD(CurrentEntry, HISTORY_BUFFER, ListEntry);
366         HistoryDeleteBuffer(HistoryBuffer);
367     }
368 }
369 
370 VOID
HistoryReshapeAllBuffers(IN PCONSRV_CONSOLE Console,IN ULONG HistoryBufferSize,IN ULONG MaxNumberOfHistoryBuffers,IN BOOLEAN HistoryNoDup)371 HistoryReshapeAllBuffers(
372     IN PCONSRV_CONSOLE Console,
373     IN ULONG HistoryBufferSize,
374     IN ULONG MaxNumberOfHistoryBuffers,
375     IN BOOLEAN HistoryNoDup)
376 {
377     PLIST_ENTRY Entry;
378     PHISTORY_BUFFER Hist;
379     NTSTATUS Status;
380 
381     // ASSERT(Console->NumberOfHistoryBuffers <= Console->MaxNumberOfHistoryBuffers);
382     if (MaxNumberOfHistoryBuffers < Console->NumberOfHistoryBuffers)
383     {
384         /*
385          * Trim the history buffers list and reduce it up to MaxNumberOfHistoryBuffers.
386          * We loop the history buffers list backwards so as to trim the oldest
387          * buffers first.
388          */
389         while (!IsListEmpty(&Console->HistoryBuffers) &&
390                (Console->NumberOfHistoryBuffers > MaxNumberOfHistoryBuffers))
391         {
392             Entry = RemoveTailList(&Console->HistoryBuffers);
393             Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
394             HistoryDeleteBuffer(Hist);
395             Console->NumberOfHistoryBuffers--;
396         }
397         ASSERT(Console->NumberOfHistoryBuffers == MaxNumberOfHistoryBuffers);
398         ASSERT(((Console->NumberOfHistoryBuffers == 0) &&  IsListEmpty(&Console->HistoryBuffers)) ||
399                ((Console->NumberOfHistoryBuffers  > 0) && !IsListEmpty(&Console->HistoryBuffers)));
400     }
401     Console->MaxNumberOfHistoryBuffers = MaxNumberOfHistoryBuffers;
402 
403     /* Resize each history buffer */
404     for (Entry = Console->HistoryBuffers.Flink;
405          Entry != &Console->HistoryBuffers;
406          Entry = Entry->Flink)
407     {
408         Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
409         Status = HistoryResizeBuffer(Hist, HistoryBufferSize);
410         if (!NT_SUCCESS(Status))
411         {
412             DPRINT1("HistoryResizeBuffer(0x%p, %lu) failed, Status 0x%08lx\n",
413                     Hist, HistoryBufferSize, Status);
414         }
415     }
416     Console->HistoryBufferSize = HistoryBufferSize;
417 
418     /* No duplicates */
419     Console->HistoryNoDup = !!HistoryNoDup;
420 }
421 
422 
423 /* PUBLIC SERVER APIS *********************************************************/
424 
425 /* API_NUMBER: ConsolepGetCommandHistory */
CON_API(SrvGetConsoleCommandHistory,CONSOLE_GETCOMMANDHISTORY,GetCommandHistoryRequest)426 CON_API(SrvGetConsoleCommandHistory,
427         CONSOLE_GETCOMMANDHISTORY, GetCommandHistoryRequest)
428 {
429     NTSTATUS Status = STATUS_SUCCESS;
430     ULONG BytesWritten = 0;
431     PHISTORY_BUFFER Hist;
432 
433     if ( !CsrValidateMessageBuffer(ApiMessage,
434                                    (PVOID*)&GetCommandHistoryRequest->History,
435                                    GetCommandHistoryRequest->HistoryLength,
436                                    sizeof(BYTE))                    ||
437          !CsrValidateMessageBuffer(ApiMessage,
438                                    (PVOID*)&GetCommandHistoryRequest->ExeName,
439                                    GetCommandHistoryRequest->ExeLength,
440                                    sizeof(BYTE)) )
441     {
442         return STATUS_INVALID_PARAMETER;
443     }
444 
445     Hist = HistoryFindBuffer(Console,
446                              GetCommandHistoryRequest->ExeName,
447                              GetCommandHistoryRequest->ExeLength,
448                              GetCommandHistoryRequest->Unicode2);
449     if (Hist)
450     {
451         ULONG i;
452 
453         LPSTR  TargetBufferA;
454         LPWSTR TargetBufferW;
455         ULONG BufferSize = GetCommandHistoryRequest->HistoryLength;
456 
457         ULONG Offset = 0;
458         ULONG SourceLength;
459 
460         if (GetCommandHistoryRequest->Unicode)
461         {
462             TargetBufferW = GetCommandHistoryRequest->History;
463             BufferSize /= sizeof(WCHAR);
464         }
465         else
466         {
467             TargetBufferA = GetCommandHistoryRequest->History;
468         }
469 
470         for (i = 0; i < Hist->NumEntries; i++)
471         {
472             SourceLength = Hist->Entries[i].Length / sizeof(WCHAR);
473             if (Offset + SourceLength + 1 > BufferSize)
474             {
475                 Status = STATUS_BUFFER_OVERFLOW;
476                 break;
477             }
478 
479             if (GetCommandHistoryRequest->Unicode)
480             {
481                 RtlCopyMemory(&TargetBufferW[Offset], Hist->Entries[i].Buffer, SourceLength * sizeof(WCHAR));
482                 Offset += SourceLength;
483                 TargetBufferW[Offset++] = L'\0';
484             }
485             else
486             {
487                 ConvertInputUnicodeToAnsi(Console,
488                                           Hist->Entries[i].Buffer, SourceLength * sizeof(WCHAR),
489                                           &TargetBufferA[Offset], SourceLength);
490                 Offset += SourceLength;
491                 TargetBufferA[Offset++] = '\0';
492             }
493         }
494 
495         if (GetCommandHistoryRequest->Unicode)
496             BytesWritten = Offset * sizeof(WCHAR);
497         else
498             BytesWritten = Offset;
499     }
500 
501     // GetCommandHistoryRequest->HistoryLength = TargetBuffer - (PBYTE)GetCommandHistoryRequest->History;
502     GetCommandHistoryRequest->HistoryLength = BytesWritten;
503 
504     return Status;
505 }
506 
507 /* API_NUMBER: ConsolepGetCommandHistoryLength */
CON_API(SrvGetConsoleCommandHistoryLength,CONSOLE_GETCOMMANDHISTORYLENGTH,GetCommandHistoryLengthRequest)508 CON_API(SrvGetConsoleCommandHistoryLength,
509         CONSOLE_GETCOMMANDHISTORYLENGTH, GetCommandHistoryLengthRequest)
510 {
511     PHISTORY_BUFFER Hist;
512     ULONG Length = 0;
513 
514     if (!CsrValidateMessageBuffer(ApiMessage,
515                                   (PVOID*)&GetCommandHistoryLengthRequest->ExeName,
516                                   GetCommandHistoryLengthRequest->ExeLength,
517                                   sizeof(BYTE)))
518     {
519         return STATUS_INVALID_PARAMETER;
520     }
521 
522     Hist = HistoryFindBuffer(Console,
523                              GetCommandHistoryLengthRequest->ExeName,
524                              GetCommandHistoryLengthRequest->ExeLength,
525                              GetCommandHistoryLengthRequest->Unicode2);
526     if (Hist)
527     {
528         ULONG i;
529         for (i = 0; i < Hist->NumEntries; i++)
530             Length += Hist->Entries[i].Length + sizeof(WCHAR); // Each entry is returned NULL-terminated
531     }
532     /*
533      * Quick and dirty way of getting the number of bytes of the
534      * corresponding ANSI string from the one in UNICODE.
535      */
536     if (!GetCommandHistoryLengthRequest->Unicode)
537         Length /= sizeof(WCHAR);
538 
539     GetCommandHistoryLengthRequest->HistoryLength = Length;
540 
541     return STATUS_SUCCESS;
542 }
543 
544 /* API_NUMBER: ConsolepExpungeCommandHistory */
CON_API(SrvExpungeConsoleCommandHistory,CONSOLE_EXPUNGECOMMANDHISTORY,ExpungeCommandHistoryRequest)545 CON_API(SrvExpungeConsoleCommandHistory,
546         CONSOLE_EXPUNGECOMMANDHISTORY, ExpungeCommandHistoryRequest)
547 {
548     PHISTORY_BUFFER Hist;
549 
550     if (!CsrValidateMessageBuffer(ApiMessage,
551                                   (PVOID*)&ExpungeCommandHistoryRequest->ExeName,
552                                   ExpungeCommandHistoryRequest->ExeLength,
553                                   sizeof(BYTE)))
554     {
555         return STATUS_INVALID_PARAMETER;
556     }
557 
558     Hist = HistoryFindBuffer(Console,
559                              ExpungeCommandHistoryRequest->ExeName,
560                              ExpungeCommandHistoryRequest->ExeLength,
561                              ExpungeCommandHistoryRequest->Unicode2);
562     HistoryDeleteBuffer(Hist);
563 
564     return STATUS_SUCCESS;
565 }
566 
567 /* API_NUMBER: ConsolepSetNumberOfCommands */
CON_API(SrvSetConsoleNumberOfCommands,CONSOLE_SETHISTORYNUMBERCOMMANDS,SetHistoryNumberCommandsRequest)568 CON_API(SrvSetConsoleNumberOfCommands,
569         CONSOLE_SETHISTORYNUMBERCOMMANDS, SetHistoryNumberCommandsRequest)
570 {
571     NTSTATUS Status = STATUS_SUCCESS;
572     PHISTORY_BUFFER Hist;
573 
574     if (!CsrValidateMessageBuffer(ApiMessage,
575                                   (PVOID*)&SetHistoryNumberCommandsRequest->ExeName,
576                                   SetHistoryNumberCommandsRequest->ExeLength,
577                                   sizeof(BYTE)))
578     {
579         return STATUS_INVALID_PARAMETER;
580     }
581 
582     Hist = HistoryFindBuffer(Console,
583                              SetHistoryNumberCommandsRequest->ExeName,
584                              SetHistoryNumberCommandsRequest->ExeLength,
585                              SetHistoryNumberCommandsRequest->Unicode2);
586     if (Hist)
587     {
588         Status = HistoryResizeBuffer(Hist, SetHistoryNumberCommandsRequest->NumCommands);
589     }
590 
591     return Status;
592 }
593 
594 /* API_NUMBER: ConsolepGetHistory */
CON_API_NOCONSOLE(SrvGetConsoleHistory,CONSOLE_GETSETHISTORYINFO,HistoryInfoRequest)595 CON_API_NOCONSOLE(SrvGetConsoleHistory,
596                   CONSOLE_GETSETHISTORYINFO, HistoryInfoRequest)
597 {
598 #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
599     NTSTATUS Status;
600     PCONSRV_CONSOLE Console;
601 
602     Status = ConSrvGetConsole(ProcessData,
603                               &Console, TRUE);
604     if (!NT_SUCCESS(Status))
605         return Status;
606 
607     HistoryInfoRequest->HistoryBufferSize      = Console->HistoryBufferSize;
608     HistoryInfoRequest->NumberOfHistoryBuffers = Console->MaxNumberOfHistoryBuffers;
609     HistoryInfoRequest->dwFlags                = (Console->HistoryNoDup ? HISTORY_NO_DUP_FLAG : 0);
610 
611     ConSrvReleaseConsole(Console, TRUE);
612     return Status;
613 #else
614     DPRINT1("%s not yet implemented\n", __FUNCTION__);
615     return STATUS_NOT_IMPLEMENTED;
616 #endif
617 }
618 
619 /* API_NUMBER: ConsolepSetHistory */
CON_API_NOCONSOLE(SrvSetConsoleHistory,CONSOLE_GETSETHISTORYINFO,HistoryInfoRequest)620 CON_API_NOCONSOLE(SrvSetConsoleHistory,
621                   CONSOLE_GETSETHISTORYINFO, HistoryInfoRequest)
622 {
623 #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
624     NTSTATUS Status;
625     PCONSRV_CONSOLE Console;
626 
627     Status = ConSrvGetConsole(ProcessData,
628                               &Console, TRUE);
629     if (!NT_SUCCESS(Status))
630         return Status;
631 
632     HistoryReshapeAllBuffers(Console,
633                              HistoryInfoRequest->HistoryBufferSize,
634                              HistoryInfoRequest->NumberOfHistoryBuffers,
635                              !!(HistoryInfoRequest->dwFlags & HISTORY_NO_DUP_FLAG));
636 
637     ConSrvReleaseConsole(Console, TRUE);
638     return STATUS_SUCCESS;
639 #else
640     DPRINT1("%s not yet implemented\n", __FUNCTION__);
641     return STATUS_NOT_IMPLEMENTED;
642 #endif
643 }
644 
645 /* API_NUMBER: ConsolepSetCommandHistoryMode */
CON_API(SrvSetConsoleCommandHistoryMode,CONSOLE_SETHISTORYMODE,SetHistoryModeRequest)646 CON_API(SrvSetConsoleCommandHistoryMode,
647         CONSOLE_SETHISTORYMODE, SetHistoryModeRequest)
648 {
649     DPRINT("SrvSetConsoleCommandHistoryMode(Mode = %d) is not yet implemented\n",
650             SetHistoryModeRequest->Mode);
651 
652     Console->InsertMode = !!(SetHistoryModeRequest->Mode & CONSOLE_OVERSTRIKE);
653     return STATUS_SUCCESS;
654 }
655 
656 /* EOF */
657