terminal support for the accepting unicode input (#162)
Support the unicode characters as input to the ssh client. PowerShell/Win32-OpenSSH#711 Remove the bAnsi related code changes to the ssh-shellhost.c as that code never executes.. Fixed "long pressing key issue for the slow ssh connections" PowerShell/Win32-OpenSSH#701 fixed warning message in the latestw_all recent commits. Fixed the issue with ssh failures in the latestw_all recent commits.
This commit is contained in:
parent
04ce306973
commit
98eca17c65
|
@ -757,10 +757,7 @@ fileio_stat(const char *path, struct _stat64 *buf)
|
|||
WIN32_FILE_ATTRIBUTE_DATA attributes = { 0 };
|
||||
int ret = -1, len = 0;
|
||||
|
||||
if ((wpath = utf8_to_utf16(path)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
memset(buf, 0, sizeof(struct _stat64));
|
||||
|
||||
/* Detect root dir */
|
||||
if (path && strcmp(path, "/") == 0) {
|
||||
|
@ -770,7 +767,7 @@ fileio_stat(const char *path, struct _stat64 *buf)
|
|||
}
|
||||
|
||||
if ((wpath = utf8_to_utf16(path)) == NULL) {
|
||||
errno = errno_from_Win32LastError();
|
||||
errno = ENOMEM;
|
||||
debug3("utf8_to_utf16 failed for file:%s error:%d", path, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
@ -781,7 +778,7 @@ fileio_stat(const char *path, struct _stat64 *buf)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
len = wcslen(wpath);
|
||||
len = (int)wcslen(wpath);
|
||||
|
||||
buf->st_ino = 0; /* Has no meaning in the FAT, HPFS, or NTFS file systems*/
|
||||
buf->st_gid = 0; /* UNIX - specific; has no meaning on windows */
|
||||
|
|
|
@ -482,10 +482,10 @@ strmode(mode_t mode, char *p)
|
|||
* As of now we are keeping "*" for everything.
|
||||
* TODO - figure out if there is a better option
|
||||
*/
|
||||
const char *permissions = "********* ";
|
||||
strncpy(p, permissions, strlen(permissions) + 1);
|
||||
|
||||
p = p + strlen(p);
|
||||
const char *permissions = "********* ";
|
||||
for(int i = 0; i < strlen(permissions); i++)
|
||||
*p++ = permissions[i];
|
||||
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
@ -535,11 +535,10 @@ static BOOL
|
|||
is_root_or_empty(wchar_t * path)
|
||||
{
|
||||
wchar_t * path_start;
|
||||
BOOL has_drive_letter_and_colon;
|
||||
int len;
|
||||
if (!path)
|
||||
return FALSE;
|
||||
len = wcslen(path);
|
||||
len = (int)wcslen(path);
|
||||
if((len > 1) && __ascii_iswalpha(path[0]) && path[1] == L':')
|
||||
path_start = path + 2;
|
||||
else
|
||||
|
|
|
@ -29,4 +29,5 @@ void convertToForwardslash(char *str);
|
|||
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
||||
int errno_from_Win32Error(int);
|
||||
void unix_time_to_file_time(ULONG, LPFILETIME);
|
||||
void file_time_unix_time(const LPFILETIME, time_t *);
|
||||
void file_time_to_unix_time(const LPFILETIME, time_t *);
|
||||
int file_attr_to_st_mode(wchar_t * path, DWORD attributes);
|
|
@ -86,39 +86,41 @@ typedef struct consoleEvent {
|
|||
} consoleEvent;
|
||||
|
||||
struct key_translation {
|
||||
char incoming[6];
|
||||
wchar_t in[6];
|
||||
int vk;
|
||||
char outgoing;
|
||||
wchar_t out;
|
||||
int in_key_len;
|
||||
} key_translation;
|
||||
|
||||
/* All the substrings (Ex- "\x1b") should be in the end, otherwise ProcessIncomingKeys() will not work as expected */
|
||||
struct key_translation keys[] = {
|
||||
{ "\x1b", VK_ESCAPE, '\x1b' },
|
||||
{ "\r", VK_RETURN, '\r' },
|
||||
{ "\b", VK_BACK, '\b' },
|
||||
{ "\x7f", VK_BACK, '\b' },
|
||||
{ "\t", VK_TAB, '\t' },
|
||||
{ "\x1b[A", VK_UP, 0 },
|
||||
{ "\x1b[B", VK_DOWN, 0 },
|
||||
{ "\x1b[C", VK_RIGHT, 0 },
|
||||
{ "\x1b[D", VK_LEFT, 0 },
|
||||
{ "\x1b[1~", VK_HOME, 0 },
|
||||
{ "\x1b[2~", VK_INSERT, 0 },
|
||||
{ "\x1b[3~", VK_DELETE, 0 },
|
||||
{ "\x1b[4~", VK_END, 0 },
|
||||
{ "\x1b[5~", VK_PRIOR, 0 },
|
||||
{ "\x1b[6~", VK_NEXT, 0 },
|
||||
{ "\x1b[11~", VK_F1, 0 },
|
||||
{ "\x1b[12~", VK_F2, 0 },
|
||||
{ "\x1b[13~", VK_F3, 0 },
|
||||
{ "\x1b[14~", VK_F4, 0 },
|
||||
{ "\x1b[15~", VK_F5, 0 },
|
||||
{ "\x1b[17~", VK_F6, 0 },
|
||||
{ "\x1b[18~", VK_F7, 0 },
|
||||
{ "\x1b[19~", VK_F8, 0 },
|
||||
{ "\x1b[20~", VK_F9, 0 },
|
||||
{ "\x1b[21~", VK_F10, 0 },
|
||||
{ "\x1b[23~", VK_F11, 0 },
|
||||
{ "\x1b[24~", VK_F12, 0 }
|
||||
{ L"\r", VK_RETURN, L'\r' , 0},
|
||||
{ L"\b", VK_BACK, L'\b' , 0},
|
||||
{ L"\x7f", VK_BACK, L'\b' , 0},
|
||||
{ L"\t", VK_TAB, L'\t' , 0},
|
||||
{ L"\x1b[A", VK_UP, 0 , 0},
|
||||
{ L"\x1b[B", VK_DOWN, 0 , 0},
|
||||
{ L"\x1b[C", VK_RIGHT, 0 , 0},
|
||||
{ L"\x1b[D", VK_LEFT, 0 , 0},
|
||||
{ L"\x1b[1~", VK_HOME, 0 , 0},
|
||||
{ L"\x1b[2~", VK_INSERT, 0 , 0},
|
||||
{ L"\x1b[3~", VK_DELETE, 0 , 0},
|
||||
{ L"\x1b[4~", VK_END, 0 , 0},
|
||||
{ L"\x1b[5~", VK_PRIOR, 0 , 0},
|
||||
{ L"\x1b[6~", VK_NEXT, 0 , 0},
|
||||
{ L"\x1b[11~", VK_F1, 0 , 0},
|
||||
{ L"\x1b[12~", VK_F2, 0 , 0},
|
||||
{ L"\x1b[13~", VK_F3, 0 , 0},
|
||||
{ L"\x1b[14~", VK_F4, 0 , 0},
|
||||
{ L"\x1b[15~", VK_F5, 0 , 0},
|
||||
{ L"\x1b[17~", VK_F6, 0 , 0},
|
||||
{ L"\x1b[18~", VK_F7, 0 , 0},
|
||||
{ L"\x1b[19~", VK_F8, 0 , 0},
|
||||
{ L"\x1b[20~", VK_F9, 0 , 0},
|
||||
{ L"\x1b[21~", VK_F10, 0 , 0},
|
||||
{ L"\x1b[23~", VK_F11, 0 , 0},
|
||||
{ L"\x1b[24~", VK_F12, 0 , 0},
|
||||
{ L"\x1b", VK_ESCAPE, L'\x1b' , 0}
|
||||
};
|
||||
|
||||
static SHORT lastX = 0;
|
||||
|
@ -130,7 +132,6 @@ consoleEvent* tail = NULL;
|
|||
BOOL bRet = FALSE;
|
||||
BOOL bNoScrollRegion = FALSE;
|
||||
BOOL bStartup = TRUE;
|
||||
BOOL bAnsi = FALSE;
|
||||
BOOL bHookEvents = FALSE;
|
||||
BOOL bFullScreen = FALSE;
|
||||
BOOL bUseAnsiEmulation = TRUE;
|
||||
|
@ -142,13 +143,12 @@ HANDLE pipe_in = INVALID_HANDLE_VALUE;
|
|||
HANDLE pipe_out = INVALID_HANDLE_VALUE;
|
||||
HANDLE pipe_err = INVALID_HANDLE_VALUE;
|
||||
HANDLE child = INVALID_HANDLE_VALUE;
|
||||
DWORD child_exit_code = 0;
|
||||
HANDLE hConsoleBuffer = INVALID_HANDLE_VALUE;
|
||||
|
||||
HANDLE monitor_thread = INVALID_HANDLE_VALUE;
|
||||
HANDLE io_thread = INVALID_HANDLE_VALUE;
|
||||
HANDLE ux_thread = INVALID_HANDLE_VALUE;
|
||||
|
||||
DWORD child_exit_code = 0;
|
||||
DWORD hostProcessId = 0;
|
||||
DWORD hostThreadId = 0;
|
||||
DWORD childProcessId = 0;
|
||||
|
@ -196,7 +196,7 @@ ConSRWidth()
|
|||
* This function will handle the console keystrokes.
|
||||
*/
|
||||
void
|
||||
SendKeyStroke(HANDLE hInput, int keyStroke, char character)
|
||||
SendKeyStroke(HANDLE hInput, int keyStroke, wchar_t character)
|
||||
{
|
||||
DWORD wr = 0;
|
||||
INPUT_RECORD ir;
|
||||
|
@ -207,32 +207,48 @@ SendKeyStroke(HANDLE hInput, int keyStroke, char character)
|
|||
ir.Event.KeyEvent.wVirtualKeyCode = keyStroke;
|
||||
ir.Event.KeyEvent.wVirtualScanCode = 0;
|
||||
ir.Event.KeyEvent.dwControlKeyState = 0;
|
||||
ir.Event.KeyEvent.uChar.UnicodeChar = 0;
|
||||
ir.Event.KeyEvent.uChar.AsciiChar = character;
|
||||
ir.Event.KeyEvent.uChar.UnicodeChar = character;
|
||||
|
||||
WriteConsoleInputA(hInput, &ir, 1, &wr);
|
||||
WriteConsoleInputW(hInput, &ir, 1, &wr);
|
||||
|
||||
ir.Event.KeyEvent.bKeyDown = FALSE;
|
||||
WriteConsoleInputA(hInput, &ir, 1, &wr);
|
||||
WriteConsoleInputW(hInput, &ir, 1, &wr);
|
||||
}
|
||||
|
||||
void
|
||||
initialize_keylen()
|
||||
{
|
||||
for(int i = 0; i < ARRAYSIZE(keys); i++)
|
||||
keys[i].in_key_len = (int) wcslen(keys[i].in);
|
||||
}
|
||||
|
||||
void
|
||||
ProcessIncomingKeys(char * ansikey)
|
||||
{
|
||||
int keylen = (int) strlen(ansikey);
|
||||
|
||||
if (!keylen)
|
||||
return;
|
||||
|
||||
for (int nKey=0; nKey < ARRAYSIZE(keys); nKey++) {
|
||||
if (strcmp(ansikey, keys[nKey].incoming) == 0) {
|
||||
SendKeyStroke(child_in, keys[nKey].vk, keys[nKey].outgoing);
|
||||
return;
|
||||
}
|
||||
wchar_t *buf = utf8_to_utf16(ansikey);
|
||||
|
||||
if (!buf) {
|
||||
printf("\nFailed to deserialize the client data, error:%d\n", GetLastError());
|
||||
exit(255);
|
||||
}
|
||||
|
||||
for (int i=0; i < keylen; i++)
|
||||
SendKeyStroke(child_in, 0, ansikey[i]);
|
||||
loop:
|
||||
while (buf && (wcslen(buf) > 0)) {
|
||||
for (int j = 0; j < ARRAYSIZE(keys); j++) {
|
||||
if ( (wcslen(buf) >= keys[j].in_key_len) && (wcsncmp(buf, keys[j].in, keys[j].in_key_len) == 0) ) {
|
||||
SendKeyStroke(child_in, keys[j].vk, keys[j].out);
|
||||
buf += keys[j].in_key_len;
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
|
||||
if (*buf == L'\x3') /*Ctrl+C - Raise Ctrl+C*/
|
||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||
else
|
||||
SendKeyStroke(child_in, 0, *buf);
|
||||
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -458,8 +474,7 @@ SizeWindow(HANDLE hInput)
|
|||
matchingFont.dwFontSize.X = 0;
|
||||
matchingFont.dwFontSize.Y = 16;
|
||||
matchingFont.FontFamily = FF_DONTCARE;
|
||||
matchingFont.FontWeight = FW_NORMAL;
|
||||
//wcscpy(matchingFont.FaceName, L"Consolas");
|
||||
matchingFont.FontWeight = FW_NORMAL;
|
||||
wcscpy_s(matchingFont.FaceName, LF_FACESIZE, L"Consolas");
|
||||
|
||||
bSuccess = __SetCurrentConsoleFontEx(child_out, FALSE, &matchingFont);
|
||||
|
@ -741,19 +756,6 @@ ProcessEvent(void *p)
|
|||
DWORD WINAPI
|
||||
ProcessEventQueue(LPVOID p)
|
||||
{
|
||||
if (child_in != INVALID_HANDLE_VALUE && child_in != NULL &&
|
||||
child_out != INVALID_HANDLE_VALUE && child_out != NULL) {
|
||||
DWORD dwInputMode;
|
||||
DWORD dwOutputMode;
|
||||
|
||||
if (GetConsoleMode(child_in, &dwInputMode) && GetConsoleMode(child_out, &dwOutputMode))
|
||||
if (((dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING) &&
|
||||
((dwInputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) == ENABLE_VIRTUAL_TERMINAL_INPUT))
|
||||
bAnsi = TRUE;
|
||||
else
|
||||
bAnsi = FALSE;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (head) {
|
||||
EnterCriticalSection(&criticalSection);
|
||||
|
@ -853,32 +855,18 @@ DWORD WINAPI
|
|||
ProcessPipes(LPVOID p)
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD dwStatus;
|
||||
DWORD dwStatus;
|
||||
char buf[128];
|
||||
|
||||
/* process data from pipe_in and route appropriately */
|
||||
while (1) {
|
||||
while (1) {
|
||||
ZeroMemory(buf, sizeof(buf));
|
||||
int rd = 0;
|
||||
|
||||
GOTO_CLEANUP_ON_FALSE(ReadFile(pipe_in, buf, sizeof(buf) - 1, &rd, NULL)); /* read bufsize-1 */
|
||||
bStartup = FALSE;
|
||||
for (int i=0; i < rd; i++) {
|
||||
if (buf[i] == 0)
|
||||
break;
|
||||
|
||||
if (buf[i] == 3) { /*Ctrl+C - Raise Ctrl+C*/
|
||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bAnsi)
|
||||
SendKeyStroke(child_in, 0, buf[i]);
|
||||
else {
|
||||
ProcessIncomingKeys(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(rd > 0)
|
||||
ProcessIncomingKeys(buf);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
@ -964,8 +952,8 @@ start_with_pty(wchar_t *command)
|
|||
HMODULE hm_kernel32 = NULL, hm_user32 = NULL;
|
||||
|
||||
if(cmd == NULL) {
|
||||
printf("ssh-shellhost - out of memory");
|
||||
return -1;
|
||||
printf("ssh-shellhost is out of memory");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ((hm_kernel32 = LoadLibraryW(L"kernel32.dll")) == NULL ||
|
||||
|
@ -1047,6 +1035,8 @@ start_with_pty(wchar_t *command)
|
|||
|
||||
/* disable Ctrl+C hander in this process*/
|
||||
SetConsoleCtrlHandler(NULL, TRUE);
|
||||
|
||||
initialize_keylen();
|
||||
|
||||
io_thread = CreateThread(NULL, 0, ProcessPipes, NULL, 0, NULL);
|
||||
if (IS_INVALID_HANDLE(io_thread))
|
||||
|
@ -1118,6 +1108,11 @@ start_withno_pty(wchar_t *command)
|
|||
char buf[128];
|
||||
DWORD rd = 0, wr = 0, i = 0;
|
||||
|
||||
if (cmd == NULL) {
|
||||
printf("ssh-shellhost is out of memory");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
pipe_in = GetStdHandle(STD_INPUT_HANDLE);
|
||||
pipe_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
pipe_err = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
|
|
@ -100,7 +100,6 @@ opendir(const char *name)
|
|||
DIR *pdir;
|
||||
wchar_t searchstr[PATH_MAX];
|
||||
wchar_t* wname = NULL;
|
||||
int needed;
|
||||
size_t len;
|
||||
|
||||
/* Detect root dir */
|
||||
|
|
|
@ -367,9 +367,9 @@ int register_child(void* child, unsigned long pid);
|
|||
|
||||
int do_exec_windows(Session *s, const char *command, int pty) {
|
||||
int pipein[2], pipeout[2], pipeerr[2], r;
|
||||
char *exec_command = NULL, *progdir = w32_programdir(), *cmd = NULL, *shell_host = NULL, *command_b64 = NULL, *argp = NULL;
|
||||
char *exec_command = NULL, *progdir = w32_programdir(), *cmd = NULL, *shell_host = NULL, *command_b64 = NULL;
|
||||
wchar_t *exec_command_w = NULL, *pw_dir_w;
|
||||
const char *sftp_exe = "sftp-server.exe";
|
||||
const char *sftp_exe = "sftp-server.exe", *argp = NULL;
|
||||
size_t command_b64_len = 0;
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFOW si;
|
||||
|
|
Loading…
Reference in New Issue