Merge pull request #357 from mihmig/master

Add far2l terminal extensions support
This commit is contained in:
Cyd
2022-01-18 19:22:39 +01:00
committed by GitHub
10 changed files with 1017 additions and 18 deletions
+2 -2
View File
@@ -1295,8 +1295,8 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
gppb(sesskey, "HideMousePtr", false, conf, CONF_hide_mouseptr);
gppb(sesskey, "SunkenEdge", false, conf, CONF_sunken_edge);
gppi(sesskey, "WindowBorder", 1, conf, CONF_window_border);
gppi(sesskey, "CurType", 0, conf, CONF_cursor_type);
gppb(sesskey, "BlinkCur", false, conf, CONF_blink_cur);
gppi(sesskey, "CurType", 1, conf, CONF_cursor_type);
gppb(sesskey, "BlinkCur", true, conf, CONF_blink_cur);
/* pedantic compiler tells me I can't use conf, CONF_beep as an int * :-) */
gppi(sesskey, "Beep", 1, conf, CONF_beep);
gppi(sesskey, "BeepInd", 0, conf, CONF_beep_ind);
+592 -1
View File
@@ -13,6 +13,10 @@
#include "putty.h"
#include "terminal.h"
/* base64 library - needed for far2l extensions support */
#include <windows/cencode.h>
#include <windows/cdecode.h>
#ifdef MOD_PERSO
#include "charset.h"
int get_param( const char * val ) ;
@@ -2000,6 +2004,10 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win)
* that need it.
*/
term = snew(Terminal);
/* far2l */
term->far2l_ext = 0; // far2l extensions mode is enabled?
term->is_apc = 0; // currently processing incoming APC sequence?
term->clip_allowed = -1; // remote clipboard access is enabled?
term->win = win;
term->ucsdata = ucsdata;
term->conf = conf_copy(myconf);
@@ -3204,6 +3212,577 @@ static void toggle_mode(Terminal *term, int mode, int query, bool state)
*/
static void do_osc(Terminal *term)
{
/* far2l extensions support */
if (term->is_apc) {
#ifndef _WINDOWS
#define DWORD unsigned int
#define WORD unsigned short
#endif
if (strncmp(term->osc_string, "far2l", 5) == 0) {
// okay, this is far2l terminal extensions APC sequence
// for more info about far2l terminal extensions please see:
// https://github.com/cyd01/KiTTY/issues/74
// https://github.com/elfmz/far2l/blob/master/WinPort/FarTTY.h
if (strncmp(term->osc_string+5, "1", 1) == 0) {
// extensions mode on
term->far2l_ext = 1;
char *reply_buf = dupprintf(
"\x1b_far2lok\x07");
ldisc_send(term->ldisc, reply_buf, strlen(reply_buf),
false);
sfree(reply_buf);
// reset clipboard state; todo: do it on session init!
term->clip_allowed = -1;
} else if (strncmp(term->osc_string+5, "0", 1) == 0) {
// extensions mode off
term->far2l_ext = 0;
// reset clipboard state; todo: do it on session init!
term->clip_allowed = -1;
} else if (strncmp(term->osc_string+5, ":", 1) == 0) {
// processing actual payload
// base64-decode payload
base64_decodestate _d_state;
base64_init_decodestate(&_d_state);
char* d_out = malloc(term->osc_strlen);
int d_count = base64_decode_block(
term->osc_string+6, term->osc_strlen-6, d_out, &_d_state);
// last byte is id
BYTE id = d_out[d_count-1];
char* reply = 0;
int reply_size = 0;
if (term->osc_strlen == OSC_STR_MAX) {
// it's possibly too large clipboard
// we can't deal with it
// until implementing dynamic osc_string allocation
#ifdef _WINDOWS
MessageBox(wgs.term_hwnd, "Too large clipboard :(", "Error", MB_OK);
#endif
// correct request id is lost forever
// so we can not prevent far2l from hanging
// so sad
// fixme: good idea is to free all allocated memory here, though
exit(100);
}
DWORD len;
// next from the end byte is command
switch (d_out[d_count-2]) {
case 'f':; // FARTTY_INTERRACT_SET_FKEY_TITLES
reply_size = 5;
reply = malloc(reply_size);
// fixme: unimplemented
DWORD zero = 0;
memcpy(reply, &zero, sizeof(DWORD));
break;
case 'n':; // FARTTY_INTERRACT_DESKTOP_NOTIFICATION
/* // not ready yet
// todo: generate some reply
// todo: show notification only if window is out of focus
// todo: remove icon after notification timeout or by mouse click
// title length, source, utf8, no zero-terminate, bytes
DWORD len1;
memcpy(&len1, d_out+d_count-6, sizeof(len1));
// text length, source, utf8, no zero-terminate, bytes
DWORD len2;
memcpy(&len2, d_out+d_count-6-4-len1, sizeof(len2));
// destination (wide char)
LPWSTR text_wc, title_wc;
int textsz_wc, titlesz_wc;
// notification may contain file names in non-latin
// or may have localized title
// so we can not assume ascii here and should do
// full utf8->multibyte conversion
titlesz_wc = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)(d_out+len2+4), len1, 0, 0);
textsz_wc = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len2, 0, 0);
if (titlesz_wc && textsz_wc) {
title_wc = malloc((titlesz_wc+1)*sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, (LPCCH)(d_out+len2+4), len1, title_wc, titlesz_wc);
text_wc = malloc((textsz_wc+1)*sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len2, text_wc, textsz_wc);
title_wc[titlesz_wc] = 0;
text_wc[textsz_wc] = 0;
NOTIFYICONDATAW pnid;
// todo: do this on window focus also
pnid.cbSize = sizeof(pnid);
pnid.hWnd = wgs.term_hwnd;
pnid.hIcon = LoadIcon(0, IDI_APPLICATION);
pnid.uID = 200;
Shell_NotifyIconW(NIM_DELETE, &pnid);
// todo: use putty icon
pnid.cbSize = sizeof(pnid);
pnid.hWnd = wgs.term_hwnd;
pnid.hIcon = LoadIcon(0, IDI_APPLICATION);
pnid.uID = 200;
pnid.uFlags = NIF_ICON | NIF_INFO | NIF_MESSAGE;
pnid.uCallbackMessage = (WM_USER + 200);
pnid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND;
memcpy(pnid.szInfoTitle, title_wc, (titlesz_wc+1)*sizeof(wchar_t));
memcpy(pnid.szInfo, text_wc, (textsz_wc+1)*sizeof(wchar_t));
Shell_NotifyIconW(NIM_ADD, &pnid);
free(text_wc);
free(title_wc);
}
*/
break;
case 'w': // FARTTY_INTERRACT_GET_WINDOW_MAXSIZE
// get largest console window size
reply_size = 5;
reply = malloc(reply_size);
// fixme: unimplemented
// here should be short x and short y
DWORD none = 0;
memcpy(reply, &none, sizeof(DWORD));
break;
case 'c': // FARTTY_INTERRACT_CLIPBOARD
// clipboard interaction
// next from the end byte is subcommand
switch (d_out[d_count-3]) {
case 'r':; // FARTTY_INTERRACT_CLIP_REGISTER_FORMAT
// register format
memcpy(&len, d_out + d_count - 3 - 4, sizeof(DWORD));
d_out[len] = 0; // zero-terminate format name
#ifdef _WINDOWS
// far2l sends format name as (utf8?) string,
// which actually containing ascii only
// so we can just call ascii function
uint32_t status = RegisterClipboardFormatA(d_out);
#endif
reply_size = 5;
reply = malloc(reply_size);
#ifdef _WINDOWS
memcpy(reply, &status, sizeof(uint32_t));
#else
bzero(reply, sizeof(uint32_t));
#endif
break;
case 'e':; // FARTTY_INTERRACT_CLIP_EMPTY
#ifdef _WINDOWS
char ec_status = 0;
if (term->clip_allowed == 1) {
OpenClipboard(wgs.term_hwnd);
ec_status = EmptyClipboard() ? 1 : 0;
CloseClipboard();
}
#endif
reply_size = 2;
reply = malloc(reply_size);
#ifdef _WINDOWS
reply[0] = ec_status;
#else
reply[0] = 0;
#endif
break;
case 'a':; // FARTTY_INTERRACT_CLIP_ISAVAIL
uint32_t a_fmt;
memcpy(&a_fmt, d_out + d_count - 3 - 4, sizeof(uint32_t));
#ifdef _WINDOWS
char out = IsClipboardFormatAvailable(a_fmt) ? 1 : 0;
#endif
reply_size = 2;
reply = malloc(reply_size);
#ifdef _WINDOWS
reply[0] = out;
#else
reply[0] = 0;
#endif
break;
case 'o':; // FARTTY_INTERRACT_CLIP_OPEN
// open
// next from the end 4 bytes is client_id length
memcpy(&len, d_out + d_count - 3 - 4, sizeof(DWORD));
d_out[len] = 0; // all remaining string is client id, make it zero terminated
// todo: check/store client id, all that stuff
reply_size = 2;
reply = malloc(reply_size);
#ifdef _WINDOWS
if (term->clip_allowed == -1) {
int status = MessageBox(wgs.term_hwnd,
"Allow far2l clipboard sync?", "PyTTY", MB_OKCANCEL);
if (status == IDOK) {
term->clip_allowed = 1;
} else {
// IDCANCEL
term->clip_allowed = 0;
}
}
// status is first response byte
if (term->clip_allowed == 1) {
reply[0] = 1;
} else {
reply[0] = -1;
}
#else
reply[0] = -1;
#endif
break;
case 's':; // FARTTY_INTERRACT_CLIP_SETDATA
// set data
if (term->clip_allowed == 1 && d_count >= 4 + 4 + 3) {
#ifdef _WINDOWS
uint32_t fmt;
char* buffer = NULL;
int BufferSize = 0;
memcpy(&fmt, d_out + d_count - 3 - 4, sizeof(uint32_t));
// id, 'c', 's', 4-byte fmt, next goes 4-byte len
memcpy(&len, d_out + d_count - 3 - 4 - 4, sizeof(DWORD));
if (len > d_count - 3 - 4 - 4)
len = d_count - 3 - 4 - 4;
if (fmt == CF_TEXT) {
int cnt = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len, NULL, 0);
if (cnt > 0) {
buffer = calloc(cnt + 1, sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len, (PWCHAR)buffer, cnt);
}
fmt = CF_UNICODETEXT;
BufferSize = (wcslen((PWCHAR)buffer) + 1) * sizeof(WCHAR);
} else if (fmt == CF_UNICODETEXT) {
// very stupid utf32->utf16 'conversion'
buffer = calloc((len / sizeof(uint32_t)) + 1, sizeof(wchar_t));
for (int i=0; i < len / sizeof(uint32_t); ++i) {
memcpy(
&buffer[i * sizeof(wchar_t)],
&d_out[i * sizeof(uint32_t)],
sizeof(wchar_t)
);
}
BufferSize = (wcslen((PWCHAR)buffer) + 1) * sizeof(WCHAR);
} else if (fmt >= 0xC000) {
// no transcoding - copy it as is
buffer = malloc(len);
memcpy(buffer, &d_out[0], len);
BufferSize = len;
}
// clipboard stuff itself
HGLOBAL hData;
void *GData;
bool set_successful = 0;
if (buffer && (hData=GlobalAlloc(GMEM_MOVEABLE,BufferSize))) {
if ((GData=GlobalLock(hData))) {
memcpy(GData,buffer,BufferSize);
GlobalUnlock(hData);
if (OpenClipboard(wgs.term_hwnd)) {
if (!SetClipboardData(fmt, (HANDLE)hData)) {
GlobalFree(hData);
} else {
set_successful = 1;
}
CloseClipboard();
} else {
GlobalFree(hData);
}
} else {
GlobalFree(hData);
}
}
free(buffer);
#endif
// prepare reply
reply_size = 2;
reply = malloc(reply_size);
// first reply byte is status
#ifdef _WINDOWS
reply[0] = set_successful;
#else
reply[0] = 0;
#endif
} else {
reply_size = 2;
reply = malloc(reply_size);
reply[0] = 0;
}
break;
case 'g':; // FARTTY_INTERRACT_CLIP_GETDATA
if (term->clip_allowed == 1) {
#ifdef _WINDOWS
uint32_t gfmt;
memcpy(&gfmt, d_out + d_count - 3 - 4, sizeof(uint32_t));
// clipboard stuff itself
void *ClipText = NULL;
int32_t ClipTextSize = 0;
if ((gfmt == CF_TEXT || gfmt == CF_UNICODETEXT || gfmt >= 0xC000) &&
OpenClipboard(wgs.term_hwnd))
{
HANDLE hClipData = GetClipboardData((gfmt == CF_TEXT) ? CF_UNICODETEXT : gfmt);
if (hClipData)
{
void *pClipData=GlobalLock(hClipData);
if (pClipData)
{
size_t n = GlobalSize(hClipData);
if (gfmt == CF_TEXT) {
ClipTextSize = WideCharToMultiByte(
CP_UTF8,
0,
(wchar_t *)pClipData,
n,
NULL,
0,
NULL,
NULL
) + 1;
if (ClipTextSize >= 0) {
n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t));
ClipText = calloc(ClipTextSize + 1, 1);
if (ClipText) {
WideCharToMultiByte(
CP_UTF8,
0,
(wchar_t *)pClipData,
n,
(char *)ClipText,
ClipTextSize,
NULL,
NULL
);
ClipTextSize = strlen((char *)ClipText) + 1;
}
}
} else if (gfmt == CF_UNICODETEXT) {
n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t));
ClipText = calloc((n + 1), sizeof(uint32_t));
if (ClipText) {
for (size_t i = 0; i < n; ++i) {
((uint32_t *)ClipText)[i] = ((uint16_t *)pClipData)[i];
}
ClipTextSize = (n + 1) * sizeof(uint32_t);
}
} else {
ClipText = malloc(n);
if (ClipText) {
memcpy(ClipText, pClipData, n);
ClipTextSize = n;
}
}
GlobalUnlock(hClipData);
}
} else {
// todo: process errors
}
CloseClipboard();
}
if (!ClipText || ClipTextSize <= 0) {
// clipboard is empty
reply_size = 5; // 4 bytes for size and one for id
reply = calloc(1, reply_size);
} else {
// + length (4 bytes) + id (1 byte)
reply_size = ClipTextSize + 5;
reply = calloc(1, reply_size);
memcpy(reply, ClipText, ClipTextSize);
// set size
memcpy(reply + ClipTextSize, &ClipTextSize, sizeof(ClipTextSize));
}
free(ClipText);
#else
reply_size = 5;
reply = calloc(1, reply_size);
#endif
} else {
// we should never reach here
// anyway, mimic empty clipboard
reply_size = 5;
reply = calloc(1, reply_size);
}
break;
}
break;
}
free(d_out);
if (reply_size > 0) {
// request is correct and we should send reply
// last byte is always id
reply[reply_size-1] = id;
// ok, let us try to answer something
// base64-encode
// result in null-terminated char* out
base64_encodestate _state;
base64_init_encodestate(&_state);
char* out = malloc(reply_size*2);
int count = base64_encode_block((char*)reply, reply_size, out, &_state);
// finishing '=' characters
char* next_char = out + count;
switch (_state.step)
{
case step_B:
*next_char++ = base64_encode_value(_state.result);
*next_char++ = '=';
*next_char++ = '=';
break;
case step_C:
*next_char++ = base64_encode_value(_state.result);
*next_char++ = '=';
break;
case step_A:
break;
}
count = next_char - out;
out[count] = 0;
// send escape seq
char* str = "\x1b_far2l";
backend_send(term->backend, str, strlen(str));
backend_send(term->backend, out, count);
char* str2 = "\x07";
backend_send(term->backend, str2, strlen(str2));
// don't forget to free memory :)
free(reply);
free(out);
}
}
}
term->osc_strlen = 0;
term->is_apc = 0;
} else
if (term->osc_w) {
while (term->osc_strlen--)
term->wordness[(unsigned char)
@@ -4119,7 +4698,15 @@ static void term_out(Terminal *term)
term->esc_args[0] = ARG_DEFAULT;
term->esc_query = 0;
break;
case ']': /* OSC: xterm escape sequences */
case '_': /* far2l: processing APC is almost the same as processing OSC */
term->is_apc = 1;
//break;
//case SEEN_APC:
/* todo */
// if (!WriteStr2TC(fdout, enable ? "\x1b_far2l1\x1b\\\x1b[5n" : "\x1b_far2l0\x07\x1b[5n"))
// if (!WriteStr2TC(fdout, enable ? "\x1b_far2l1\x1b\\\x1b[5n" : "\x1b_far2l0\x07\x1b[5n"))
//break;
case ']': /* OSC: xterm escape sequences */
/* Compatibility is nasty here, xterm, linux, decterm yuk! */
compatibility(OTHER);
term->termstate = SEEN_OSC;
@@ -5340,6 +5927,10 @@ static void term_out(Terminal *term)
} else {
term->termstate = OSC_STRING;
term->osc_strlen = 0;
/* far2l */
if (term->is_apc) {
term->osc_string[term->osc_strlen++] = (char)c;
}
}
}
break;
+15 -2
View File
@@ -6,6 +6,9 @@
* but for the moment, this will do.
*/
#include <windows/winseat.h>
extern WinGuiSeat wgs;
#ifndef PUTTY_TERMINAL_H
#define PUTTY_TERMINAL_H
@@ -185,11 +188,20 @@ struct terminal_tag {
#define ANSI(x,y) ((x)+((y)*256))
#define ANSI_QUE(x) ANSI(x,1)
#define OSC_STR_MAX 2048
/* far2l extensions support */
//#define OSC_STR_MAX 2048
// todo: allocate osc_string dynamically
#define OSC_STR_MAX 1048576
int osc_strlen;
char osc_string[OSC_STR_MAX + 1];
bool osc_w;
/* far2l */
int far2l_ext; // extensions mode on
bool is_apc; // currently processing APC sequence
int clip_allowed; // remote clipboard access is allowed
char id_string[1024];
unsigned char *tabs;
@@ -205,7 +217,8 @@ struct terminal_tag {
SEEN_OSC_P,
OSC_STRING, OSC_MAYBE_ST,
VT52_ESC,
/* far2l extensions support */ SEEN_APC,
VT52_ESC,
VT52_Y1,
VT52_Y2,
VT52_FG,
+7
View File
@@ -418,6 +418,7 @@ putty.exe: agentf.o aqsync.o be_all_s.o be_misc.o callback.o cmdline.o \
winnps.o winpgntc.o winprint.o winproxy.o winsecur.o \
winselgui.o winser.o winshare.o winstore.o wintime.o \
winucs.o winutils.o winx11.o x11fwd.o \
cencode.o cdecode.o \
adb.o \
kitty.o kitty_commun.o kitty_crypt.o kitty_image.o kitty_proxy.o kitty_registry.o kitty_ssh.o \
kitty_store.o kitty_tools.o kitty_win.o \
@@ -447,6 +448,7 @@ putty.exe: agentf.o aqsync.o be_all_s.o be_misc.o callback.o cmdline.o \
winnps.o winpgntc.o winprint.o winproxy.o winsecur.o \
winselgui.o winser.o winshare.o winstore.o wintime.o \
winucs.o winutils.o winx11.o x11fwd.o \
cencode.o cdecode.o \
adb.o \
kitty.o kitty_commun.o kitty_crypt.o kitty_image.o kitty_proxy.o kitty_registry.o kitty_ssh.o \
kitty_store.o kitty_tools.o kitty_win.o \
@@ -528,6 +530,11 @@ testcrypt.exe: ecc.o marshal.o memory.o millerrabin.o mpint.o mpunsafe.o \
sshpubk.o sshrsa.o sshrsag.o sshsh256.o sshsh512.o sshsha.o \
sshsha3.o testcrypt.o tree234.o utils.o winmiscs.o
cencode.o: ../windows/cencode.c
$(CC) $(COMPAT) $(CFLAGS) $(XFLAGS) -c ../windows/cencode.c
cdecode.o: ../windows/cencode.c
$(CC) $(COMPAT) $(CFLAGS) $(XFLAGS) -c ../windows/cdecode.c
agentf.o: ../agentf.c ../putty.h ../ssh.h ../pageant.h ../sshchan.h \
../defs.h ../puttyps.h ../network.h ../misc.h ../marshal.h \
+88
View File
@@ -0,0 +1,88 @@
/*
cdecoder.c - c source to a base64 decoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include <cdecode.h>
int base64_decode_value(char value_in)
{
static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
static const char decoding_size = sizeof(decoding);
value_in -= 43;
if (value_in < 0 || value_in > decoding_size) return -1;
return decoding[(int)value_in];
}
void base64_init_decodestate(base64_decodestate* state_in)
{
state_in->step = step_a;
state_in->plainchar = 0;
}
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
{
const char* codechar = code_in;
char* plainchar = plaintext_out;
char fragment;
*plainchar = state_in->plainchar;
switch (state_in->step)
{
while (1)
{
case step_a:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_a;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2;
case step_b:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_b;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4;
case step_c:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_c;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6;
case step_d:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_d;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03f);
}
}
/* control should not reach here */
return plainchar - plaintext_out;
}
+28
View File
@@ -0,0 +1,28 @@
/*
cdecode.h - c header for a base64 decoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#ifndef BASE64_CDECODE_H
#define BASE64_CDECODE_H
typedef enum
{
step_a, step_b, step_c, step_d
} base64_decodestep;
typedef struct
{
base64_decodestep step;
char plainchar;
} base64_decodestate;
void base64_init_decodestate(base64_decodestate* state_in);
int base64_decode_value(char value_in);
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
#endif /* BASE64_CDECODE_H */
+109
View File
@@ -0,0 +1,109 @@
/*
cencoder.c - c source to a base64 encoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include <cencode.h>
const int CHARS_PER_LINE = 72;
void base64_init_encodestate(base64_encodestate* state_in)
{
state_in->step = step_A;
state_in->result = 0;
state_in->stepcount = 0;
}
char base64_encode_value(char value_in)
{
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (value_in > 63) return '=';
return encoding[(int)value_in];
}
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
{
const char* plainchar = plaintext_in;
const char* const plaintextend = plaintext_in + length_in;
char* codechar = code_out;
char result;
char fragment;
result = state_in->result;
switch (state_in->step)
{
while (1)
{
case step_A:
if (plainchar == plaintextend)
{
state_in->result = result;
state_in->step = step_A;
return codechar - code_out;
}
fragment = *plainchar++;
result = (fragment & 0x0fc) >> 2;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x003) << 4;
case step_B:
if (plainchar == plaintextend)
{
state_in->result = result;
state_in->step = step_B;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0f0) >> 4;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2;
case step_C:
if (plainchar == plaintextend)
{
state_in->result = result;
state_in->step = step_C;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0c0) >> 6;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*codechar++ = base64_encode_value(result);
++(state_in->stepcount);
if (state_in->stepcount == CHARS_PER_LINE/4)
{
//*codechar++ = '\n';
state_in->stepcount = 0;
}
}
}
/* control should not reach here */
return codechar - code_out;
}
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
{
char* codechar = code_out;
switch (state_in->step)
{
case step_B:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
*codechar++ = '=';
break;
case step_C:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
break;
case step_A:
break;
}
//*codechar++ = '\n';
return codechar - code_out;
}
+31
View File
@@ -0,0 +1,31 @@
/*
cencode.h - c header for a base64 encoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#ifndef BASE64_CENCODE_H
#define BASE64_CENCODE_H
typedef enum
{
step_A, step_B, step_C
} base64_encodestep;
typedef struct
{
base64_encodestep step;
char result;
int stepcount;
} base64_encodestate;
void base64_init_encodestate(base64_encodestate* state_in);
char base64_encode_value(char value_in);
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
#endif /* BASE64_CENCODE_H */
+143 -13
View File
@@ -10,6 +10,10 @@
#include <limits.h>
#include <assert.h>
/* far2l extensions support - base64 encode/decode libs */
#include <cencode.h>
#include <cdecode.h>
#ifdef __WINE__
#define NO_MULTIMON /* winelib doesn't have this */
#endif
@@ -436,7 +440,7 @@ int WINAPI Agent_WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show
#endif
#ifdef MOD_WTS
typedef enum _WTS_VIRTUAL_CLASS { WTSVirtualClientData, WTSVirtualFileHandle } WTS_VIRTUAL_CLASS; // WTS_VIRTUAL_CLASS n'est pas défini dans le fichier wtsapi32.h !!!
//typedef enum _WTS_VIRTUAL_CLASS { WTSVirtualClientData, WTSVirtualFileHandle } WTS_VIRTUAL_CLASS; // WTS_VIRTUAL_CLASS n'est pas défini dans le fichier wtsapi32.h !!!
#include <wtsapi32.h>
#endif
#if (defined MOD_BACKGROUNDIMAGE) && (!defined FLJ)
@@ -612,7 +616,9 @@ static const SeatVtable win_seat_vt = {
.interactive = nullseat_interactive_yes,
.get_cursor_position = win_seat_get_cursor_position,
};
static WinGuiSeat wgs = { .seat.vt = &win_seat_vt,
// "static" removed by far2l extensions support patch
// we need to access wgs from terminal.c to open dialog boxes, etc
WinGuiSeat wgs = { .seat.vt = &win_seat_vt,
.logpolicy.vt = &win_gui_logpolicy_vt };
#ifdef MOD_PERSO
@@ -4827,10 +4833,17 @@ free(cmd);
ignore_clip = wParam; /* don't panic on DESTROYCLIPBOARD */
break;
case WM_DESTROYCLIPBOARD:
if (!ignore_clip)
term_lost_clipboard_ownership(term, CLIP_SYSTEM);
ignore_clip = false;
return 0;
/* far2l extensions support */
// In far2l extensions mode we should not do anything here,
// clipboard is handled by far2l extensions.
if (!(term->far2l_ext == 1) || (!term->clip_allowed)) {
if (!ignore_clip)
term_lost_clipboard_ownership(term, CLIP_SYSTEM);
ignore_clip = false;
}
return 0;
case WM_PAINT: {
PAINTSTRUCT p;
#if (defined MOD_BACKGROUNDIMAGE) && (!defined FLJ)
@@ -5591,13 +5604,130 @@ if( (GetKeyState(VK_MENU)&0x8000) && (wParam==VK_SPACE) ) {
*/
noise_ultralight(NOISE_SOURCE_KEY, lParam);
/*
* We don't do TranslateMessage since it disassociates the
* resulting CHAR message from the KEYDOWN that sparked it,
* which we occasionally don't want. Instead, we process
* KEYDOWN, and call the Win32 translator functions so that
* we get the translations under _our_ control.
*/
/* far2l extensions support */
if (term->far2l_ext) {
// extensions mode enabled
// far2l_ext keyboard input event structure
WORD repeat; // 2 bytes
WORD vkc; // 2 bytes
WORD vsc; // 2 bytes
DWORD ctrl; // 4 bytes
DWORD uchar; // 4 bytes
CHAR type; // 1 byte
// set repeat, virtual keycode, virtual scancode
repeat = LOWORD(lParam);
vsc = HIWORD(lParam) & 0xFF;
vkc = LOWORD(wParam);
// this fixes far2l's "editor autocomplete" plugin behavior
if ((vkc == VK_TAB) || (vkc == VK_BACK) || (vkc == VK_ESCAPE) || (vkc == VK_DELETE)) {
vsc = 0;
}
// fixes strange alt+arrows behavior
if ((vkc == VK_LEFT) || (vkc == VK_RIGHT) || (vkc == VK_UP) || (vkc == VK_DOWN)) {
vsc = 0;
}
// set control keys state
ctrl = 0;
if (GetAsyncKeyState(VK_LCONTROL)) { ctrl |= LEFT_CTRL_PRESSED; }
if (GetAsyncKeyState(VK_RCONTROL)) { ctrl |= RIGHT_CTRL_PRESSED; }
if (GetAsyncKeyState(VK_LMENU)) { ctrl |= LEFT_ALT_PRESSED; }
if (GetAsyncKeyState(VK_RMENU)) { ctrl |= RIGHT_ALT_PRESSED; }
if (GetAsyncKeyState(VK_SHIFT)) { ctrl |= SHIFT_PRESSED; }
// begin: reserved for future usage
// Console WinAPI does not allow us to distinguish between left and right
// shift keys. But PuTTY is not a console app, so why not to send
// all information about control keys state that we actually have here?
// Using bits not used by any other status for backward compatibility.
#define RIGHT_SHIFT_PRESSED 0x1000
#define LEFT_SHIFT_PRESSED 0x2000
if (GetAsyncKeyState(VK_LSHIFT)) { ctrl |= RIGHT_SHIFT_PRESSED; }
if (GetAsyncKeyState(VK_RSHIFT)) { ctrl |= LEFT_SHIFT_PRESSED; }
// end
if ((lParam & ( 1 << 24 )) >> 24) { ctrl |= ENHANCED_KEY; }
if ((((u_short)GetKeyState(VK_NUMLOCK)) & 0xffff) != 0) { ctrl |= NUMLOCK_ON; }
if ((((u_short)GetKeyState(VK_SCROLL)) & 0xffff) != 0) { ctrl |= SCROLLLOCK_ON; }
if ((((u_short)GetKeyState(VK_CAPITAL)) & 0xffff) != 0) { ctrl |= CAPSLOCK_ON; }
// set unicode character
BYTE kb[256];
GetKeyboardState(kb);
WCHAR uc[5] = {};
ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0);
// todo: check result
//int result = ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0);
uchar = uc[0];
// set event type
if ((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN)) {
type = 'K';
} else {
type = 'k';
}
char* kev = malloc(15); // keyboard event structure length
memcpy(kev, &repeat, sizeof(repeat));
memcpy(kev + 2, &vkc, sizeof(vkc));
memcpy(kev + 4, &vsc, sizeof(vsc));
memcpy(kev + 6, &ctrl, sizeof(ctrl));
memcpy(kev + 10, &uchar, sizeof(uchar));
memcpy(kev + 14, &type, sizeof(type));
// base64-encode kev
// result in null-terminated char* out
base64_encodestate _state;
base64_init_encodestate(&_state);
char* out = malloc(15*2);
int count = base64_encode_block(kev, 15, out, &_state);
// finishing '=' characters
char* next_char = out + count;
switch (_state.step)
{
case step_B:
*next_char++ = base64_encode_value(_state.result);
*next_char++ = '=';
*next_char++ = '=';
break;
case step_C:
*next_char++ = base64_encode_value(_state.result);
*next_char++ = '=';
break;
case step_A:
break;
}
count = next_char - out;
out[count] = 0;
// send escape seq
char* str = "\x1b_f2l";
backend_send(backend, str, strlen(str));
backend_send(backend, out, count);
char* str2 = "\x07";
backend_send(backend, str2, strlen(str2));
// don't forget to free memory :)
free(out);
// we should not do any other key processing in this mode
return 0;
}
/*
* We don't do TranslateMessage since it disassociates the
* resulting CHAR message from the KEYDOWN that sparked it,
* which we occasionally don't want. Instead, we process
* KEYDOWN, and call the Win32 translator functions so that
* we get the translations under _our_ control.
*/
{
unsigned char buf[20];
int len;
+2
View File
@@ -3,6 +3,8 @@
* and windlg.c.
*/
#pragma once
typedef struct WinGuiSeat WinGuiSeat;
struct WinGuiSeat {